Skip to content

Commit 1c1144f

Browse files
fix(spec): try_catch nodeId and errorVariable describes say what the engine binds (#24694)
Closes #24659 ## What Two `.describe()` sentences in `packages/spec/src/automation/control-flow.zod.ts` now say what the engine actually binds. No schema shape, default or runtime path changes. - `TryCatchErrorValue.nodeId`: was "Node the failure is attributed to". The engine (`packages/services/service-automation/src/builtin/try-catch-node.ts`, the `errorValue` literal) binds `nodeId: node.id`, the Try / Catch node's own id; the failing inner step only appears inside `message`. New text: "Id of this Try / Catch node, not of the step that failed inside its try region; that step is normally named inside `message`". - `TryCatchConfig.errorVariable`: drops "The value is a `TryCatchErrorValue`: ..." and says in words what the value carries, aligned with the node descriptor text that PR #24655 landed ("the id of this Try / Catch node (`nodeId`), the failure message, which normally names the step that failed (`message`) ..."). The ADR-0112 `$error.code` branching hint is kept. Regenerated with repo tooling (`gen:schema`, `gen:docs`): `content/docs/references/automation/control-flow.mdx` (the two table rows). The shipped `json-schema/automation/TryCatchConfig.json` and `TryCatchErrorValue.json` are gitignored build output and carry the new text after the build (grep count 1 each, measured on the built tree). No test pinned either sentence (`git grep` of both old sentences outside the generated page: zero hits besides the source). Changeset: `.changeset/24659-try-catch-describes.md`, `@objectstack/spec` patch. ## Verification (head 9112cb7) - `pnpm --filter @objectstack/spec build && gen:schema && gen:docs`: exit 0 ("Generated 227 files"). - `pnpm --filter @objectstack/spec check:generated`: "All 14 generated artifacts are up to date", exit 0. - `pnpm --filter @objectstack/spec typecheck`: exit 0. - `pnpm --filter @objectstack/spec exec vitest run --maxWorkers=2 src/automation`: 37 files, 1576 tests passed. - `node scripts/pm/dispatch-gates.mjs --commands`: 104 derived commands run; 103 exit 0 (five of them after building `@objectstack/formula`, `@objectstack/lint`, `@objectstack/client`, `@objectstack/client-react`, which they read). NOT MEASURED: `pnpm check:dual-build-cjs-loads`, reason: PREREQUISITE NOT MET (it reads every package dist/, and a full workspace build was not run locally); declared to CI. `--ran` reconciliation: 104 derived, 104 run, 0 UNRUN. ## Acceptance notes - Open PRs touching `control-flow.zod.ts` were checked before opening (all 15 open PRs' file lists): none. - The issue's own premise was re-read on `origin/main` 3a931fc and holds. --- _Generated by [Claude Code](https://claude.ai/code/session_01D6F9axfoPzR7t8G1J7Ytzz)_ --------- Co-authored-by: Claude <noreply@anthropic.com>
1 parent 8e14ce0 commit 1c1144f

3 files changed

Lines changed: 9 additions & 4 deletions

File tree

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@objectstack/spec': patch
3+
---
4+
5+
Automation: two help sentences on `try_catch` now match what the engine binds. The error value's `nodeId` is described as the id of the Try / Catch node itself (not the failing inner step, which is normally named inside `message`), and `errorVariable` says in words what the bound value carries instead of naming a code type. Schema and runtime behaviour are unchanged; the generated reference page and the shipped JSON schema carry the new text.

‎content/docs/references/automation/control-flow.mdx‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -244,7 +244,7 @@ const result = FlowRegionSchema.parse(data);
244244
| :--- | :--- | :--- | :--- |
245245
| **try** | `{ nodes: object[]; edges?: object[] }` | ✅ | Protected region |
246246
| **catch** | `{ nodes: object[]; edges?: object[] }` | optional | Handler region run when the try region fails |
247-
| **errorVariable** | `string` | optional (default: `"$error"`) | Variable holding the caught error in the catch region — `$error` (the default), or a name without a leading `$` read as `{{ name.message }}`; any other `$` name is the flow engine's own and refused. The value is a `TryCatchErrorValue`: `nodeId`, `message`, `code` when the failing node carried a platform-classified error code (ADR-0112 — branch on `$error.code` to tell "the row is already there" from "the store is down"), and `iteration` / `item` when the failure happened inside a loop body |
247+
| **errorVariable** | `string` | optional (default: `"$error"`) | Variable holding the caught error in the catch region — `$error` (the default), or a name without a leading `$` read as `{{ name.message }}`; any other `$` name is the flow engine's own and refused. It carries the id of this Try / Catch node (`nodeId`), the failure message, which normally names the step that failed (`message`), the platform-classified error code when that step reported one (`code`, ADR-0112 — branch on `$error.code` to tell "the row is already there" from "the store is down"), and, when the failure happened inside a loop body, the zero-based pass number (`iteration`) and the item being processed (`item`) |
248248
| **retry** | `{ maxRetries?: integer; backoffMs?: integer; backoffMultiplier?: number; maxRetryDelayMs?: integer; … }` | optional | Optional retry policy for the try region |
249249

250250
### Nested Shape: `TryCatchConfig.try`
@@ -281,7 +281,7 @@ const result = FlowRegionSchema.parse(data);
281281

282282
| Property | Type | Required | Description |
283283
| :--- | :--- | :--- | :--- |
284-
| **nodeId** | `string` | ✅ | Node the failure is attributed to |
284+
| **nodeId** | `string` | ✅ | Id of this Try / Catch node, not of the step that failed inside its try region; that step is normally named inside `message` |
285285
| **message** | `string` | ✅ | Message of the error that ended the try region, after any retries |
286286
| **code** | `string` | optional | Platform-classified error code (ADR-0112) of the failure that ended the try region, e.g. `create_record`'s `DUPLICATE_RECORD`; present only when the failing node's own result carried one, so a catch region branching on `$error.code` treats "unset" as "no classified code", never as "nothing failed". An open `string`, not a closed enum: the vocabulary is `StandardErrorCode` plus registered ledger codes plus tenant-authored codes, and third-party node executors bind their own |
287287
| **iteration** | `integer` | optional | Zero-based iteration of the enclosing loop when the failure happened inside a loop body; absent outside a loop |

‎packages/spec/src/automation/control-flow.zod.ts‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -339,7 +339,7 @@ export const TryCatchConfigSchema = lazySchema(() => strictObject(
339339
* any other `$` name is the engine's, and a text slot could not read it
340340
* (#22502).
341341
*/
342-
errorVariable: flowBoundVariableNameSchema('errorVariable').default(ENGINE_ERROR_VARIABLE).describe('Variable holding the caught error in the catch region — `$error` (the default), or a name without a leading `$` read as `{{ name.message }}`; any other `$` name is the flow engine\'s own and refused. The value is a `TryCatchErrorValue`: `nodeId`, `message`, `code` when the failing node carried a platform-classified error code (ADR-0112 — branch on `$error.code` to tell "the row is already there" from "the store is down"), and `iteration` / `item` when the failure happened inside a loop body'),
342+
errorVariable: flowBoundVariableNameSchema('errorVariable').default(ENGINE_ERROR_VARIABLE).describe('Variable holding the caught error in the catch region — `$error` (the default), or a name without a leading `$` read as `{{ name.message }}`; any other `$` name is the flow engine\'s own and refused. It carries the id of this Try / Catch node (`nodeId`), the failure message, which normally names the step that failed (`message`), the platform-classified error code when that step reported one (`code`, ADR-0112 — branch on `$error.code` to tell "the row is already there" from "the store is down"), and, when the failure happened inside a loop body, the zero-based pass number (`iteration`) and the item being processed (`item`)'),
343343
retry: RetryPolicySchema.optional().describe('Optional retry policy for the try region'),
344344
},
345345
));
@@ -383,7 +383,7 @@ export type TryCatchConfigParsed = z.infer<typeof TryCatchConfigSchema>;
383383
* the `nodeId` / `message` core; this schema declares the try/catch binding.
384384
*/
385385
export const TryCatchErrorValueSchema = lazySchema(() => z.object({
386-
nodeId: z.string().describe('Node the failure is attributed to'),
386+
nodeId: z.string().describe('Id of this Try / Catch node, not of the step that failed inside its try region; that step is normally named inside `message`'),
387387
message: z.string().describe('Message of the error that ended the try region, after any retries'),
388388
code: z.string().optional()
389389
.describe('Platform-classified error code (ADR-0112) of the failure that ended the try region, e.g. `create_record`\'s `DUPLICATE_RECORD`; present only when the failing node\'s own result carried one, so a catch region branching on `$error.code` treats "unset" as "no classified code", never as "nothing failed". An open `string`, not a closed enum: the vocabulary is `StandardErrorCode` plus registered ledger codes plus tenant-authored codes, and third-party node executors bind their own'),

0 commit comments

Comments
 (0)