Skip to content

Fix Orchestrator.__repr__ crash on partially-initialized instances#5073

Closed
gospartan wants to merge 1 commit into
facebook:mainfrom
gospartan:export-D97166104
Closed

Fix Orchestrator.__repr__ crash on partially-initialized instances#5073
gospartan wants to merge 1 commit into
facebook:mainfrom
gospartan:export-D97166104

Conversation

@gospartan
Copy link
Copy Markdown
Contributor

Summary:
Fix AttributeError in Orchestrator.__repr__() when the object is only
partially initialized. The method checked hasattr(self, "experiment") but
did not check hasattr(self, "generation_strategy"), causing a crash when
__repr__ was called between the two attribute assignments.

Bug details:

Orchestrator.__init__ sets attributes in this order:

self.experiment = experiment           # line 228
self._set_logger(options=options)      # line 231
self.options = options                 # line 232
self.generation_strategy = generation_strategy  # line 235

If any error occurs between lines 228-235 (e.g. in _set_logger), then
self.experiment exists but self.generation_strategy does not.

The log_usage() decorator on OrcOpticsScheduler.__init__ catches such
errors and calls repr(args) to log them. Since args[0] is the partially-
initialized scheduler instance, this triggers Orchestrator.__repr__():

def __repr__(self) -> str:
    if not hasattr(self, "experiment"):       # True -- experiment IS set
        return f"{self.__class__.__name__}"
    return (
        f"...generation_strategy={self.generation_strategy}..."  # BOOM
    )

The secondary AttributeError replaces the original error, making the real
failure impossible to diagnose.

Example: FBLearner run f1051747930 failed with:

AttributeError: 'OrcOpticsScheduler' object has no attribute 'generation_strategy'

Stack trace: OrcOpticsScheduler.__init__ -> Orchestrator.__init__ ->
(error between lines 228-235) -> log_usage error handler ->
repr(args) -> Orchestrator.__repr__ -> self.generation_strategy crash.

The actual root cause was completely masked by this __repr__ bug.

Fix: Add hasattr(self, "generation_strategy") guard alongside the
existing hasattr(self, "experiment") check.

Differential Revision: D97166104

Summary:
Fix `AttributeError` in `Orchestrator.__repr__()` when the object is only
partially initialized. The method checked `hasattr(self, "experiment")` but
did not check `hasattr(self, "generation_strategy")`, causing a crash when
`__repr__` was called between the two attribute assignments.

**Bug details:**

`Orchestrator.__init__` sets attributes in this order:
```
self.experiment = experiment           # line 228
self._set_logger(options=options)      # line 231
self.options = options                 # line 232
self.generation_strategy = generation_strategy  # line 235
```

If any error occurs between lines 228-235 (e.g. in `_set_logger`), then
`self.experiment` exists but `self.generation_strategy` does not.

The `log_usage()` decorator on `OrcOpticsScheduler.__init__` catches such
errors and calls `repr(args)` to log them. Since `args[0]` is the partially-
initialized scheduler instance, this triggers `Orchestrator.__repr__()`:

```python
def __repr__(self) -> str:
    if not hasattr(self, "experiment"):       # True -- experiment IS set
        return f"{self.__class__.__name__}"
    return (
        f"...generation_strategy={self.generation_strategy}..."  # BOOM
    )
```

The secondary `AttributeError` replaces the original error, making the real
failure impossible to diagnose.

**Example:** FBLearner run f1051747930 failed with:
```
AttributeError: 'OrcOpticsScheduler' object has no attribute 'generation_strategy'
```
Stack trace: `OrcOpticsScheduler.__init__` -> `Orchestrator.__init__` ->
(error between lines 228-235) -> `log_usage` error handler ->
`repr(args)` -> `Orchestrator.__repr__` -> `self.generation_strategy` crash.

The actual root cause was completely masked by this `__repr__` bug.

**Fix:** Add `hasattr(self, "generation_strategy")` guard alongside the
existing `hasattr(self, "experiment")` check.

Differential Revision: D97166104
@meta-cla meta-cla Bot added the CLA Signed Do not delete this pull request or issue due to inactivity. label Mar 19, 2026
@meta-codesync
Copy link
Copy Markdown

meta-codesync Bot commented Mar 19, 2026

@gospartan has exported this pull request. If you are a Meta employee, you can view the originating Diff in D97166104.

@meta-codesync
Copy link
Copy Markdown

meta-codesync Bot commented Mar 20, 2026

This pull request has been merged in 5bff9c3.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

CLA Signed Do not delete this pull request or issue due to inactivity. fb-exported Merged meta-exported

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant