OpenHands / OpenHands/software-agent-sdk

[Bug]: ConversationService: stored fields mutated in memory before save_meta() with no rollback on failure

Open
#4,800 2 comments 1 reaction 0 assignees View on GitHub

Nobody has claimed this yet.

bug priority:low ready-for-dev session
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 — mutates stored.title, stored.tags, stored.updated_at
  • set_conversation_tag / delete_conversation_tag (via _flush_tags_mutation) — mutates stored.tags
  • AutoTitleSubscriber — mutates stored.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_tag leaves stored.tags unchanged when save_meta() raises
  • delete_conversation_tag leaves stored.tags unchanged when save_meta() raises
  • update_conversation leaves stored.title / stored.tags unchanged when save_meta() raises
  • AutoTitleSubscriber leaves stored.title unchanged when save_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

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. 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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.