Skip to content

PUT /api/v1/automation/:name answers 500 for the same four malformed flow bodies #8055 just reclassified on POST #8123

Description

@hotlong

Found while implementing #8055. Filed rather than fixed there: #8055's scope is the POST / registration route, and this is a second route.

Symptom

PUT /api/v1/automation/:name (updateFlow) makes the identicalautomationService.registerFlow(name, definition) call the POST / branch makes, in the same file, with no classification around it — packages/runtime/src/domains/automation.ts, the parts.length === 1 && m === 'PUT' branch (locate by symbol; the POST branch is the one carrying the #8055 comment).

So every body #8055 measured as a wrong-class 500 on POST is still a wrong-class 500 on PUT:

  1. a node missing label — 500 carrying a raw Zod issue array
  2. an unknown node key — 500 carrying unrecognized_keys / keys / path
  3. a malformed try_catch region — 500 try_catch 'g' try: invalid region — ...
  4. an undeclared node config key — 500 carrying the 3b — wire the flow executors to parse() their config, and tighten the undeclared-key warning into an error #4277 self-correcting message

Same two costs #7535 and #8055 spell out: a retry-on-5xx client re-sends a request that can never succeed, and an authoring agent reads "the server broke" instead of "your metadata is wrong".

Why it matters beyond the repeat

After #8055 lands, POST and PUT disagree about the class of an identical refusal on the same domain — the exact drift #7535's fix was shaped to avoid ("the two routes cannot disagree"). An author who publishes a flow through the update route gets a different answer from one who publishes through create, for the same broken definition.

Fix

One line, once #8055 is merged: wrap the PUT branch's registerFlow call the same way, reusing the flowDefinitionRefusal helper #8055 adds to that file. The helper was written module-local and route-agnostic for this. Note the PUT branch has its own body.definition ?? body unwrap, so the definition it forwards is not always the request body — worth a test case of its own.

Not licensed by this card

Widening the refusal, softening any refusal into a 200, or changing which bodies are rejected. Class and envelope only, as in #8055.

Blocked-by

Blocked-by: #8055 (the helper this reuses lands there).


Generated by Claude Code

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions