Skip to content

fix: 'dict' object has no attribute 'key' error - #263

Closed
VictorMorand wants to merge 1 commit into
experimaestro:masterfrom
VictorMorand:master
Closed

fix: 'dict' object has no attribute 'key' error#263
VictorMorand wants to merge 1 commit into
experimaestro:masterfrom
VictorMorand:master

Conversation

@VictorMorand

Copy link
Copy Markdown
Contributor

Problem

When RemoteClient receives RPC push notifications (such as JobSubmittedEvent or ExperimentJobStateEvent) containing
tags, _notification_to_event was instantiating event classes directly via event_class(**data). Standard Python
dataclass instantiation does not convert nested dicts into nested dataclasses, leaving event.tags as a list of raw
dictionaries ([{"key": "...", "value": "..."}]).

When state_provider.py subsequently accessed tag.key, it raised:

AttributeError: 'dict' object has no attribute 'key'. Did you mean: 'keys'?

This crashed the remote client read loop and disconnected the client from the server.

Solution

  1. RPC Deserialization Fix: Updated client.py to pass notification dictionaries through EventBase.from_dict(...), which
    properly deserializes nested dataclasses like JobTag and ProgressLevel.
  2. Defensive Guardrails: Updated tag extraction in state_provider.py, app.py, and state_bridge.py to handle both JobTag
    instances and dict representations safely.
  3. Wiki Update: Documented RPC event deserialization details in experimaestro-tags.md.

Testing

• Added unit test test_client_notification_to_event_job_submitted_tags in test_remote_state.py.
• Verified test suite passes:
uv run pytest experimaestro-python/src/experimaestro/tests/test_remote_state.py
uv run pytest experimaestro-python/src/experimaestro/tests/test_tags.py experimaestro-
python/src/experimaestro/tests/test_events.py

@bpiwowar

Copy link
Copy Markdown
Collaborator

Thanks @VictorMorand — good catch, and the diagnosis was exactly right. Landed on master as ad9ee27 with you as co-author.

I kept the core of your fix (routing _notification_to_event through EventBase.from_dict) and your regression test, plus the unused colorsys import removal. I dropped the defensive isinstance(tag, dict) branches in state_provider.py, tui/app.py and webui/state_bridge.py: client.py was the only deserialization site in the codebase that bypassed from_dict, so with that fixed nothing can produce dict-shaped tags any more. Those branches would also have turned a future recurrence into silently missing tags instead of a loud error.

Closing in favour of the direct commit.

@bpiwowar bpiwowar closed this Jul 31, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants