Skip to main content
← Back to list
01Issue
BugShippedSwamp CLI
Assigneesstack72

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

  1. 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 */ },
      },
    }
  2. Create an instance (swamp model create <type> m) with methods: {} (the default is defined only on the type's method schema, not in the instance). swamp model type describe <type> --json shows limit in the method arguments' required array despite the .default().

  3. Reference the method from a workflow step that does NOT supply limit:

    steps:
      - name: s
        task: { type: model_method, modelIdOrName: m, methodName: audit }
  4. 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.

02Bog Flow
OPENTRIAGEDIN PROGRESSSHIPPED+ 1 MOREASSIGNED+ 2 MOREREVIEW+ 3 MOREPR_MERGED+ 1 MORECONTRIBUTOR_NOTIFIED

Shipped

6/11/2026, 3:25:24 PM

Click a lifecycle step above to view its details.

03Sludge Pulse
stack72 assigned stack726/11/2026, 2:28:27 PM
Editable. Press Enter to edit.

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.

stack72 commented 6/11/2026, 3:25:33 PM

Thanks @jentz for reporting this! The fix has been merged and a release is on its way. We appreciate your contribution to swamp.

Sign in to post a ripple.