Summary
When a workflow run fails for a backend/infra reason (not a wiring problem), the "Fix with agent" repair turn (mode=Repair) treats it as a graph-wiring bug: it restructures a correct graph into a broken one, produces inconsistent intermediate graphs that the author-gate correctly rejects, and then dead-loops on repeated edit_workflow failures and gives up with no proposal.
Problem
Observed run (live)
A file-attachment workflow was built correctly as a 6-node native chain:
trigger -> research(agent) -> build_html(code_executor) -> upload_file(oh:storage_upload_file) -> get_link(oh:storage_get_link) -> send(GMAIL_SEND_EMAIL)
The run reached upload_file and failed with a pure backend error (unrelated to the graph):
tool_call `oh:storage_upload_file` failed: File upload failed: Backend returned 500 Internal Server Error
for POST_MULTIPART .../agent-integrations/file-storage/files: The specified bucket does not exist
(steps: research success, build_html success, upload_file error.)
What "Fix with agent" did
mode=Repair then:
- Tore out the
upload_file and get_link nodes, collapsing the correct 6-node chain back to a broken 4-node shape (trigger -> research -> build_html -> send).
- Left
send.attachment bound to =nodes.get_link.item.json.url while get_link no longer existed, so the author-gate correctly rejected the dangling reference:
required-arg resolvability check: arg resolved null in sandbox - rejecting node=send field=attachment expression==nodes.get_link.item.json.url
- Looped on
edit_workflow (4x Error), hit the middleware halt (repeated tool failure - halting run ... tool=edit_workflow step=8), and ended trail_off=true has_proposal=false - i.e. it gave up with no fix.
Root cause
The repair turn does not distinguish a backend/infra failure ("the specified bucket does not exist", a 500 from the file-storage service) from a graph-wiring failure (a null-resolved binding, a wrong slug). A backend 500 means "the graph is fine, the environment is broken" - the correct repair is to surface that and NOT touch the graph. Instead the agent assumes the wiring is wrong, restructures a correct graph, and destroys it.
Impact
- A correct, working workflow is degraded into a broken one by the repair flow whenever the backend has a transient/infra failure.
- The repair then dead-loops and delivers no proposal, so the user is left worse off than before clicking "Fix with agent".
- The graph the repair produced (4 nodes, no upload/link) cannot ever attach a file even after the backend recovers.
Steps to reproduce
- Build a workflow whose run fails for a backend reason (e.g.
oh:storage_upload_file when the file-storage bucket is misconfigured - see #5174).
- Run it; it fails at the upload step with the backend 500.
- Click "Fix with agent".
- Observe: it restructures the (correct) graph, the gate rejects inconsistent intermediates,
edit_workflow loops, and the turn ends with no proposal (trail_off).
Environment: desktop dev build, current file-attachment branch (#5148). The gate carve-out and native-tool handling in #5148 are working correctly here - the initial build was correct and the run failed loudly at the right node; this issue is strictly about the repair turn's misdiagnosis.
Solution (suspected)
The repair flow needs to classify the run's failure before acting:
- A tool_call failure whose error is a provider/backend transport error (5xx, "bucket does not exist", connection/timeouts) is not a graph bug. Surface it to the user as a backend/infra failure and do not restructure the graph. (The core already classifies budget-exhausted errors as
kind="budget" and skips them - a similar kind="backend"/"infra" classification for run failures could gate the repair.)
- Only a genuine wiring/validation failure (null-resolved required arg, unreal slug, dangling reference) should trigger a graph edit.
- Independently, the repair should not collapse a correct native file chain back to an in-agent shape - but the primary fix is the diagnosis gate above.
Acceptance criteria
Related
Summary
When a workflow run fails for a backend/infra reason (not a wiring problem), the "Fix with agent" repair turn (
mode=Repair) treats it as a graph-wiring bug: it restructures a correct graph into a broken one, produces inconsistent intermediate graphs that the author-gate correctly rejects, and then dead-loops on repeatededit_workflowfailures and gives up with no proposal.Problem
Observed run (live)
A file-attachment workflow was built correctly as a 6-node native chain:
The run reached
upload_fileand failed with a pure backend error (unrelated to the graph):(steps:
researchsuccess,build_htmlsuccess,upload_fileerror.)What "Fix with agent" did
mode=Repairthen:upload_fileandget_linknodes, collapsing the correct 6-node chain back to a broken 4-node shape (trigger -> research -> build_html -> send).send.attachmentbound to=nodes.get_link.item.json.urlwhileget_linkno longer existed, so the author-gate correctly rejected the dangling reference:edit_workflow(4xError), hit the middleware halt (repeated tool failure - halting run ... tool=edit_workflow step=8), and endedtrail_off=true has_proposal=false- i.e. it gave up with no fix.Root cause
The repair turn does not distinguish a backend/infra failure ("the specified bucket does not exist", a 500 from the file-storage service) from a graph-wiring failure (a null-resolved binding, a wrong slug). A backend 500 means "the graph is fine, the environment is broken" - the correct repair is to surface that and NOT touch the graph. Instead the agent assumes the wiring is wrong, restructures a correct graph, and destroys it.
Impact
Steps to reproduce
oh:storage_upload_filewhen the file-storage bucket is misconfigured - see #5174).edit_workflowloops, and the turn ends with no proposal (trail_off).Environment: desktop dev build, current file-attachment branch (#5148). The gate carve-out and native-tool handling in #5148 are working correctly here - the initial build was correct and the run failed loudly at the right node; this issue is strictly about the repair turn's misdiagnosis.
Solution (suspected)
The repair flow needs to classify the run's failure before acting:
kind="budget"and skips them - a similarkind="backend"/"infra"classification for run failures could gate the repair.)Acceptance criteria
edit_workflowretries andtrail_offwith no proposal.Related
oh:tool results usable and fail loudly, document the real file-attachment chain #5148 - the file-attachment PR; its gate carve-out + native-tool handling are working (the initial build was correct and the failure was surfaced loudly). This issue is about the repair turn only.