shareAI-lab/learn-claude-code · error · WorkflowInputError
resume args do not match the original run
Error message
resume args do not match the original run
What it means
On resume, _call_locked() compares caller-supplied args against the args persisted in the run snapshot: passing args=None adopts the saved args, but passing explicit args that differ raises WorkflowInputError('resume args do not match the original run'). Journal cache keys are derived from prompts built from args, so changed args would make replay ambiguous.
Source
Thrown at s16_workflow_runtime/code.py:564
if resuming:
run_id = validate_run_id(resume_from_run_id)
else:
run_id = reserve_run_id(meta)
with workflow_run_lock(run_id):
return await self._call_locked(
meta, script_fn, args, run_id, resuming
)
async def _call_locked(self, meta, script_fn, args, run_id, resuming):
if resuming:
snapshot = _read_snapshot(run_id)
if snapshot.get("workflowName") != meta["name"]:
raise WorkflowInputError("resume runId does not match workflow meta")
saved_args = snapshot.get("args", {})
if args is None:
args = saved_args
elif args != saved_args:
raise WorkflowInputError("resume args do not match the original run")
journal = WorkflowJournal(run_id, resume=True)
else:
args = args or {}
journal = WorkflowJournal(run_id, resume=False)
task_id = create_task_id(run_id)
task = LocalWorkflowTask(task_id, run_id, meta)
# Record the launch envelope before workflow execution starts.
launched = {"status": "async_launched", "taskId": task_id,
"taskType": "local_workflow", "runId": run_id,
"workflowName": meta["name"]}
task.event("async_launched", runId=run_id, taskId=task_id)
task.event("task_started", workflow=meta["name"],
phases=",".join(meta.get("phases", [])) or "-",
resume=resuming)
_write_json(STORE / f"{run_id}.json", {
"runId": run_id,
"workflowName": meta["name"],View on GitHub (pinned to 985456f4ad)
Solutions
- Omit args entirely on resume (args=None) to reuse the original run's arguments.
- Pass byte-identical args to the original call, including nested values.
- If you genuinely need different args, start a new run instead of resuming.
Example fix
# before
await run_workflow("review", args={"changes": diff_v2}, resume_from_run_id=rid)
# after
await run_workflow("review", resume_from_run_id=rid) # reuses saved args Defensive patterns
Strategy: validation
Validate before calling
from s16_workflow_runtime import _read_snapshot
saved = _read_snapshot(run_id)["args"]
if args is not None and args != saved:
raise ValueError("pass args=None or the exact original args")
await run_workflow(name, resume_from_run_id=run_id, args=args) Try / catch
try:
await run_workflow(name, args=args, resume_from_run_id=rid)
except WorkflowInputError as e:
if "args do not match" in str(e):
return await run_workflow(name, resume_from_run_id=rid) # reuse saved args
raise Prevention
- Default to args=None on resume; only pass args when you intend them to be identical.
- Persist the exact args dict you launched with (it is in the snapshot) and replay it verbatim.
- Treat 'resume with different inputs' as a new run by convention.
When it happens
Trigger: run_workflow(name, args={...}, resume_from_run_id=<id>) where the dict differs (even by one key or value) from snapshot['args'] recorded at launch.
Common situations: Tweaking the change description or options between the failed run and the resume attempt; defaults injected client-side that differ from what the original caller sent; key-order-independent dict comparison still failing on nested value changes.
Related errors
- resume runId does not match workflow meta
- resume snapshot not found for {run_id}
- invalid resume snapshot for {run_id}
- invalid workflow runId
- meta must be an object literal
AI-assisted analysis of shareAI-lab/learn-claude-code@985456f4ad (2026-08-14).
Data as JSON: /api/errors/803d731067232d43.
Report an issue: GitHub.