Skip to content

actions: z.array(z.boolean()) converts string "false" to true via map(Boolean) #16584

@hunnyboy1217

Description

@hunnyboy1217

Astro Info

Astro                    v5.x (latest)
Node                     v22.x
Package manager          pnpm
Platform                 linux

If this issue only occurs in one browser, which browser is a problem?

No response

Describe the Bug

z.array(z.boolean()) in a form action always converts every non-empty string value to true, making it impossible to pass false through a form data array.

The bug is in handleFormDataGetAll() at line 411 of packages/astro/src/actions/runtime/server.ts:

function handleFormDataGetAll(key: string, formData: FormData, validator: z.$ZodArray) {
  const entries = Array.from(formData.getAll(key));
  const elementValidator = validator._zod.def.element;
  if (elementValidator instanceof z.$ZodNumber) {
    return entries.map(Number);
  } else if (elementValidator instanceof z.$ZodBoolean) {
    return entries.map(Boolean);  // BUG: Boolean("false") === true
  }
  return entries;
}

FormData values are always strings. Boolean("false") === true and Boolean("0") === true because JavaScript's Boolean() coercion treats any non-empty string as truthy. The string "false" is not an empty string, so it becomes true.

The single-boolean path in formDataToObject() at line 389 already implements the correct logic:

} else if (validator instanceof z.$ZodBoolean) {
  const val = formData.get(prefixedKey);
  obj[key] = val === 'true' ? true : val === 'false' ? false : formData.has(prefixedKey);
}

The array path is inconsistent — it should apply the same string comparison per entry instead of map(Boolean):

return entries.map(v => v === 'true' ? true : v === 'false' ? false : Boolean(v));

The existing test suite in packages/astro/test/units/actions/form-data-to-object.test.ts covers single z.boolean() with "false" values (line 51–66) and number/string arrays, but has no test for z.array(z.boolean()).

What's the expected result?

A form submission with three boolean array values ["false", "true", "false"] should produce [false, true, false]. Currently it produces [true, true, true].

Link to Minimal Reproducible Example

https://github.com/Hunnyboy1217/astro-action-boolean-array-repr

Participation

  • I am willing to submit a pull request for this issue.

Metadata

Metadata

Assignees

No one assigned

    Labels

    - P3: minor bugAn edge case that only affects very specific usage (priority)pkg: astroRelated to the core `astro` package (scope)

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions