abhigyanpatwari/GitNexus · error · BadRequestError

Parameter "${fieldName}" must be a string

Error message

Parameter "${fieldName}" must be a string

What it means

assertString's second rejection: the value is neither a string nor an array — it is an object (qs nested syntax like ?a[b]=c), a number, boolean, null, or undefined. Route handlers use it to fail fast with a 400 naming the field rather than operating on a value that only looks like a string after a blind cast.

Source

Thrown at gitnexus/src/server/validation.ts:62

/**
 * Type guard for HTTP request parameters that must be a single string.
 *
 * Express's req.query and req.body parsers return `string | string[] | ParsedQs`
 * for any field, but route handlers commonly cast to `string` and operate on
 * `.length`. When the caller passes the same key twice (?x=a&x=b) the value
 * arrives as an array, and a `.length` check intended for the string ends up
 * counting array elements — bypassing length-based guards (CodeQL
 * js/type-confusion-through-parameter-tampering, alert at api.ts:1118).
 *
 * @throws BadRequestError when value is not a string (array, object, undefined, etc.)
 */
export function assertString(value: unknown, fieldName: string): string {
  if (typeof value !== 'string') {
    if (Array.isArray(value)) {
      throw new BadRequestError(`Parameter "${fieldName}" must be a single string, got an array`);
    }
    throw new BadRequestError(`Parameter "${fieldName}" must be a string`);
  }
  return value;
}

/**
 * Resolve a user-supplied relative path against an allowed root and verify it
 * stays inside that root. Mirrors the existing guard at api.ts:1067-1077.
 *
 * Returns the absolute resolved path. Rejects empty paths, null bytes, and
 * paths that resolve outside the root (e.g., `../../../etc/passwd`).
 *
 * @throws BadRequestError when the path is empty or contains a null byte
 * @throws ForbiddenError when the resolved path escapes the root
 */
export function assertSafePath(rawPath: string, root: string): string {
  if (rawPath.length === 0) {
    throw new BadRequestError('Path must not be empty');
  }

View on GitHub (pinned to aac7515d2a)

Solutions

  1. Send the field as a plain string in the query string or JSON body
  2. Check the endpoint's documented parameter type and fix the client payload
  3. Avoid bracket syntax (?a[b]=c) for scalar fields — it parses as an object
  4. Validate the request DTO client-side (zod/valibot) before sending

Example fix

// before
fetch('/api/search?name[user]=1');   // nested object → 400
fetch('/api/search', { body: JSON.stringify({ name: 42 }) });

// after
fetch('/api/search?name=foo');
fetch('/api/search', { body: JSON.stringify({ name: 'foo' }) });
Defensive patterns

Strategy: type-guard

Validate before calling

const body = { name: String(rawName ?? '') };
if (!body.name) throw new Error('name must be a non-empty string');

Type guard

function isStringParam(v: unknown): v is string {
  return typeof v === 'string';
}

Prevention

When it happens

Trigger: Hitting a route that asserts a field when the parsed value is a qs nested object (?name[user]=1), a JSON body with the wrong scalar type ({"name": 42} or null), or a field explicitly passed as undefined.

Common situations: JSON API clients sending numbers where a string id/name is expected; Express's extended query parser turning bracket syntax into objects; copy-pasted or template-built payloads with wrong types.

Related errors


AI-assisted analysis of abhigyanpatwari/GitNexus@aac7515d2a (2026-08-20). Data as JSON: /api/errors/bbc66696e1576737. Report an issue: GitHub.