OpenHands / OpenHands/software-agent-sdk
[Bug]: ConversationService: stored fields mutated in memory before save_meta() with no rollback on failure
Nobody has claimed this yet.
- Dominant language
- Python
- Stars
- 1.1k
- Forks
- 539
- Avg merge
- 1d 19h
- Merged PRs (30d)
- 137
Description
ConversationService has a recurring pattern where fields on StoredConversation are mutated in memory before the corresponding save_meta() call persists them to meta.json. If save_meta() fails (disk full, ownership lost, etc.), the in-memory state is ahead of disk. After eviction or restart, the change silently disappears.
This currently affects at least three places:
update_conversation— mutatesstored.title,stored.tags,stored.updated_atset_conversation_tag/delete_conversation_tag(via_flush_tags_mutation) — mutatesstored.tagsAutoTitleSubscriber— mutatesstored.title,stored.updated_at
Actual Behavior
When save_meta() raises after an in-memory mutation, the change is visible in-process but not persisted. After eviction or restart the mutation disappears silently. The following pytest demonstrates the gap:
# pytest tests/agent_server/test_conversation_tags.py::test_set_tag_rolls_back_on_save_failure
from unittest.mock import patch
with patch.object(event_service, "save_meta", side_effect=RuntimeError("disk full")):
with pytest.raises(RuntimeError):
await service.set_conversation_tag(conv_id, "key", "value")
assert "key" not in event_service.stored.tags # currently fails — key is present despite failed persist
Run with:
pytest tests/agent_server/test_conversation_tags.py
Acceptance Criteria
-
set_conversation_tagleavesstored.tagsunchanged whensave_meta()raises -
delete_conversation_tagleavesstored.tagsunchanged whensave_meta()raises -
update_conversationleavesstored.title/stored.tagsunchanged whensave_meta()raises -
AutoTitleSubscriberleavesstored.titleunchanged whensave_meta()raises
The cleanest fix is reversing the order — write to disk first, then update in-memory state — rather than adding rollback logic after the fact. Not a blocker, but worth addressing consistently across all affected sites rather than piecemeal.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Inspect ConversationService methods update_conversation, set_conversation_tag, delete_conversation_tag, and _flush_tags_mutation, then follow the AutoTitleSubscriber path. Start with tests/agent_server/test_conversation_tags.py and run its pytest suite, adding failure cases for save_meta() errors. Done means each listed mutation leaves in-memory fields unchanged when persistence fails.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- python
- Domain
- backend
- Issue type
- Bug
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Active
- Clarity
- Clearly specified
- Newbie friendliness
- 72/100