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
- Send the field as a plain string in the query string or JSON body
- Check the endpoint's documented parameter type and fix the client payload
- Avoid bracket syntax (?a[b]=c) for scalar fields — it parses as an object
- 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
- Validate request DTOs with a schema library (zod/valibot) before sending
- Avoid bracket syntax (?a[b]=c) for scalar fields — it parses as an object
- Keep JSON body types aligned with the endpoint's documented types
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
- Parameter "${fieldName}" must be a single string, got an arr
- "url" must be a string
- Uploaded folder has no usable name
- Upload must be a folder
- Path must not be empty
AI-assisted analysis of abhigyanpatwari/GitNexus@aac7515d2a (2026-08-20).
Data as JSON: /api/errors/bbc66696e1576737.
Report an issue: GitHub.