Relationships
#617 workflow validate: method args with a Zod .default() are treated as required
Opened by jentz · 6/11/2026· Shipped 6/11/2026
Description
When a model type's method arguments (or globalArguments) Zod schema declares a field with .default(...), the JSON Schema swamp generates from it still lists that field in required. swamp workflow validate's step-input check (#40) then treats an optional, defaulted argument as mandatory and fails a step that omits it — even though the method runs fine using the default.
This is adjacent to #359 (false "Missing required inputs" when the arg is set in the model definition) but distinct: here the argument is not supplied anywhere — the type schema's .default() should make it optional, and it does not.
Steps to reproduce
An extension model type whose method has a defaulted argument:
methods: { audit: { arguments: z.object({ limit: z.number().int().min(1).max(100).default(15), }), execute: async (_a, ctx) => { /* ... uses args.limit ?? 15 */ }, }, }
Create an instance (
swamp model create <type> m) withmethods: {}(the default is defined only on the type's method schema, not in the instance).swamp model type describe <type> --jsonshowslimitin the method arguments'requiredarray despite the.default().Reference the method from a workflow step that does NOT supply
limit:steps: - name: s task: { type: model_method, modelIdOrName: m, methodName: audit }
swamp workflow validate <wf> --json.
Expected
A Zod field with .default(...) is optional: it should be omitted from the
generated JSON Schema required, and swamp workflow validate should pass a
step that omits it (the default applies at runtime).
Actual
- Defaulted fields are emitted in
required. - The step-input check fails:
Step inputs for '<step>' (m.audit) -> false. swamp model method run m audit(no--input) runs fine using the default, confirming the requirement is spurious.
Workaround
Supply the defaulted argument explicitly in the workflow step inputs:
(e.g. limit: 15).
Suggested fix
Treat Zod ZodDefault (and ZodOptional) as not-required during the
zod -> JSON-Schema conversion; and/or have the step-input check treat a schema
default as satisfying the requirement (same spirit as the #359 fix, applied to
defaults rather than definition-supplied args).
Environment
Observed on swamp 20260608.234005.0-sha.ed5f78a4 (an update to
20260610.225536.0-sha.4559c368 is available; please verify whether the #359
fix already covers the .default() case). Schemas authored with Zod v4.
Shipped
Click a lifecycle step above to view its details.
4chems commented 6/11/2026, 7:23:33 AM
Confirmed, and it is a regression with a clean version boundary: the same repository validated green on 20260508.001043.0-sha.3d787176 and fails immediately after updating to 20260610.225536.0-sha.4559c368, with Missing required inputs: <field> for every workflow step that omits a .default()ed method argument (six fields across three local extension models in our case — z.boolean().default(false), z.array(z.string()).default([]), z.string().default("groups")).
Workaround that unblocked us: declare the affected arguments .optional() (documenting the default in .describe()) and apply the default inside execute via destructuring defaults / ??. Validation passes again and runtime behavior is unchanged, but it degrades the schema — type describe no longer advertises the default value.
A guess at the cause given the timing: if the JSON Schema generation moved to Zod 4's native toJSONSchema, its default io: "output" mode lists ZodDefault fields as required (they are always present on output), while io: "input" treats them as optional. Method arguments are an input schema, so converting with io: "input" would restore the pre-20260610 behavior.
Sign in to post a ripple.