Skip to content

fix(workflow-executor): accept null title/prompt/aiConfigName in step definitions#1753

Open
Scra3 wants to merge 1 commit into
mainfrom
fix/workflow-executor-null-step-definition-fields
Open

fix(workflow-executor): accept null title/prompt/aiConfigName in step definitions#1753
Scra3 wants to merge 1 commit into
mainfrom
fix/workflow-executor-null-step-definition-fields

Conversation

@Scra3

@Scra3 Scra3 commented Jul 10, 2026

Copy link
Copy Markdown
Member

Why

A customer running migrated browser-engine workflows on the orchestrator hit Internal validation error occurred while preparing the step (DomainValidationError). The orchestrator serializes missing BPMN attributes as JSON null (DOM getAttribute semantics — see bpmn-parser.ts getPrompt() returning null explicitly), while the executor's shared step-definition fields used z.string().optional(), which accepts undefined but rejects null.

What

  • title / prompt / aiConfigName now accept null and normalize it to undefined (.nullish().transform()), keeping the inferred output type string | undefined for all consumers.
  • The wire types (ServerWorkflowStepBase) now tell the truth: title: string | null, prompt?: string | null.
  • Tests: a task and a condition with title: null / prompt: null map successfully.

Companion server-side fix: unnamed manual gateways no longer hard-fail BPMN parsing (browser-engine parity) — ForestAdmin/forestadmin-server fix/workflow-unnamed-manual-gateways.

🤖 Generated with Claude Code

Note

Accept null title, prompt, and aiConfigName in workflow step definitions

  • Adds an optionalString zod helper in step-definition.ts that accepts null or undefined and normalizes both to undefined after parsing.
  • Updates sharedFields to use this helper for prompt, aiConfigName, and title, replacing z.string().optional().
  • Updates ServerWorkflowStepBase and ServerWorkflowTaskBase in server-types.ts to reflect the broadened types.
  • Adds mapper tests covering null title/prompt for conditions and tasks.

Macroscope summarized ee29ae0.

… definitions

The orchestrator serializes missing BPMN attributes as JSON null (DOM
getAttribute), not absent keys — z.string().optional() rejected null and
an unnamed gateway or promptless step failed with an opaque
DomainValidationError while preparing the step.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@qltysh

qltysh Bot commented Jul 10, 2026

Copy link
Copy Markdown

Qlty


Coverage Impact

This PR will not change total coverage.

Modified Files with Diff Coverage (1)

RatingFile% DiffUncovered Line #s
Coverage rating: A Coverage rating: A
packages/workflow-executor/src/types/validated/step-definition.ts100.0%
Total100.0%
🚦 See full report on Qlty Cloud »

🛟 Help
  • Diff Coverage: Coverage for added or modified lines of code (excludes deleted files). Learn more.

  • Total Coverage: Coverage for the whole repository, calculated as the sum of all File Coverage. Learn more.

  • File Coverage: Covered Lines divided by Covered Lines plus Missed Lines. (Excludes non-executable lines including blank lines and comments.)

    • Indirect Changes: Changes to File Coverage for files that were not modified in this PR. Learn more.

@hercemer42

Copy link
Copy Markdown
Contributor

Reviewed — the fix itself is correct and independently safe (pure widening: null normalized to undefined, inferred types unchanged for consumers, wire types now honest). Mergeable as-is, with one checklist item and one important caveat on the PR description.

Checklist before merge: title/prompt/aiConfigName aren't the only getAttribute-derived wire fields. Please confirm executionType and mcpServerId can never arrive as JSON null (transitions' answer/buttonText are already null-tolerant via the filter in mapCondition).

The "Why" misattributes the customer symptom. title: null cannot produce "Internal validation error occurred while preparing the step" — that message belongs to DomainValidationError, and a null title fails earlier, in toStepDefinition's bare .parse() (step-definition-mapper.ts), as a raw ZodError. getAvailableRuns treats that as unexpected (not a WorkflowExecutorError), logs it, and never reports the run as malformed — so the run silently loops (claim → drop → lock release → re-claim), with no user-visible error at all. The customer-visible DomainValidationError on their Get Data step is a different bug: the executor's CollectionSchemaSchema rejecting their forest-rails apimap (hand-authored smart-field types, and [null] types from array columns the liana can't map — get_type_for has no else branch and the 2019 drop-guard misses the array case). Neither this PR nor the server PR fixes that — a third fix (server-side type sanitization in getCollectionSchema, or a .catch(null) on the executor's field type) is still needed before the customer's workflows run.

Sequencing: this must be released — and installed at customers — before ForestAdmin/forestadmin-server#8360 deploys; details in my comment there.

🤖 Posted by Claude Code on Brian's behalf

@hercemer42

Copy link
Copy Markdown
Contributor

The collection-schema fix referenced in the review comment (the actual cause of the customer's "Internal validation error … preparing this step" on Get Data) is now open: ForestAdmin/forestadmin-server#8361. Server-side, no executor release needed, mergeable independently of this PR.

🤖 Posted by Claude Code on Brian's behalf

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.

2 participants