Skip to content

parseAsDateTime and other parsers fail on null/undefined when used with parseAsArrayOf #1055

@AfeefRazick

Description

@AfeefRazick

Context

What's your version of nuqs?

"nuqs": "^2.4.3"

What framework are you using?

✅ React SPA (no router)
✅ React Router

Which version of your framework are you using?

"react": "19.0.0"
"react-dom": "19.0.0"
"react-router": "7.1.5"

Description

When using parseAsDateTime on a singular field, null works fine — calling setState(null) bypasses the serializer, so no errors occur (as in the docs examples).

However, when wrapping parseAsDateTime in parseAsArrayOf (e.g., for date ranges), the serializer fails if any array element is null or undefined. This happens because the serializer calls .toISOString() on a nullish value.

Example:

parseAsArrayOf(parseAsDateTime)
// Intended to handle: [Date, undefined]

Instead, it throws because undefined (or null) is passed to .toISOString().

Relevant parser code (parseAsIsoDateTime):

export const parseAsIsoDateTime: ParserBuilder<Date> = createParser({
  parse: v => {
    const date = new Date(v)
    if (Number.isNaN(date.valueOf())) {
      return null
    }
    return date
  },
  serialize: (v: Date) => v.toISOString(),
  eq: compareDates
})

Why it fails:

In array contexts, each element is run through serialize without checking for null/undefined. Standalone parseAsDateTime works fine because null never hits the serializer.

Suggested fix:

serialize: (v: Date | null | undefined) => (v === null || v === undefined ? '' : v.toISOString()),

This ensures that nullish values inside arrays are handled consistently.

Note:
This issue is likely not limited to parseAsDateTime. Other built-in parsers without nullish checks in serialize may behave the same when used inside parseAsArrayOf.

Reproduction

Steps to reproduce:

Create a state with useQueryStates using parseAsArrayOf(parseAsDateTime).

Set the value to [new Date(), undefined] or [new Date(), null].

Observe that .toISOString() is called on the nullish value, causing an error.

Minimal example:

const [dateRange, setDateRange] = useQueryStates({
  range: parseAsArrayOf(parseAsDateTime)
});

// This will throw
setDateRange({ range: [new Date(), undefined] });

Metadata

Metadata

Assignees

No one assigned

    Labels

    cannot-reproduceEither no reproduction provided, or cannot reproduce with a minimal setupparsers/built-inRelated to built-in parsers

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions