Skip to content

fix: hydrate approval resume via Flow._state, not the read-only property - #72

Merged
Sirajmx merged 1 commit into
IABTechLab:mainfrom
aleksUIX:fix/67-resume-readonly-flow-state
Sep 15, 2026
Merged

Sirajmx merged 1 commit into
IABTechLab:mainfrom
aleksUIX:fix/67-resume-readonly-flow-state

Conversation

@aleksUIX

Copy link
Copy Markdown
Contributor

Summary

Fixes #67. POST /approvals/{id}/resume 500s after a successful decide. _resume_proposal_flow assigned flow.state = ProposalState(**snapshot). CrewAI 1.15 made Flow.state a read-only @property, so __setattr__ raises AttributeError: property 'state' of 'ProposalHandlingFlow' object has no setter. Decide still writes the approval; only resume blows up.

The property reads the _state PrivateAttr. Existing tests already hydrate that way (flow._state = state in test_proposal_error_taxonomy.py). Resume now does the same. In-place mutation of flow.state.proposal_id etc. is unchanged.

Empty snapshots use snapshot or {} so ProposalState(**None) cannot throw.

Fix

flow = ProposalHandlingFlow()
flow._state = ProposalState(**(snapshot or {}))

Out of scope (deliberate)

Test plan

  • service: resume after approve hydrates snapshot and returns accepted
  • service: resume after reject returns rejected without assigning flow.state
  • HTTP: authenticated POST /approvals/{id}/resume after decide returns 200 (resumed_from_approval)
  • uv run --locked ruff check src/ and ruff format --check src/ tests/ clean

Closes #67

@Sirajmx Sirajmx left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Verified: full unit + integration suite passes, 0 failed, merged onto current main. Live e2e
confirms it too - resume genuinely 500s on main's CrewAI 1.15 break, 200s clean on this branch.
Merging.

@Sirajmx
Sirajmx merged commit 1a30c79 into IABTechLab:main Sep 15, 2026
6 of 8 checks passed
atc964 added a commit that referenced this pull request Sep 22, 2026
Backfill [Unreleased] entries for shipped changes that landed without
one: change-request idempotency (#64), dealless-order change requests
(#65), the OpenDirect21Client MCP session lifecycle fix (#66), the
approval resume fix (#72, issue #67), and the create-operator-key
--quiet flag (#80). Entries are written from the merged diffs.
Release automation will consume this file, so no code changes here.
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.

POST /approvals/{approval_id}/resume returns 500 for both approved and rejected decisions: assignment to read-only ProposalHandlingFlow.state

2 participants