{"record":{"id":"bbc66696e1576737","repo":"abhigyanpatwari/GitNexus","slug":"parameter-fieldname-must-be-a-string","errorCode":null,"errorMessage":"Parameter \"${fieldName}\" must be a string","messagePattern":"Parameter \"(.+?)\" must be a string","errorType":"exception","errorClass":"BadRequestError","httpStatus":400,"severity":"error","filePath":"gitnexus/src/server/validation.ts","lineNumber":62,"sourceCode":"\n/**\n * Type guard for HTTP request parameters that must be a single string.\n *\n * Express's req.query and req.body parsers return `string | string[] | ParsedQs`\n * for any field, but route handlers commonly cast to `string` and operate on\n * `.length`. When the caller passes the same key twice (?x=a&x=b) the value\n * arrives as an array, and a `.length` check intended for the string ends up\n * counting array elements — bypassing length-based guards (CodeQL\n * js/type-confusion-through-parameter-tampering, alert at api.ts:1118).\n *\n * @throws BadRequestError when value is not a string (array, object, undefined, etc.)\n */\nexport function assertString(value: unknown, fieldName: string): string {\n  if (typeof value !== 'string') {\n    if (Array.isArray(value)) {\n      throw new BadRequestError(`Parameter \"${fieldName}\" must be a single string, got an array`);\n    }\n    throw new BadRequestError(`Parameter \"${fieldName}\" must be a string`);\n  }\n  return value;\n}\n\n/**\n * Resolve a user-supplied relative path against an allowed root and verify it\n * stays inside that root. Mirrors the existing guard at api.ts:1067-1077.\n *\n * Returns the absolute resolved path. Rejects empty paths, null bytes, and\n * paths that resolve outside the root (e.g., `../../../etc/passwd`).\n *\n * @throws BadRequestError when the path is empty or contains a null byte\n * @throws ForbiddenError when the resolved path escapes the root\n */\nexport function assertSafePath(rawPath: string, root: string): string {\n  if (rawPath.length === 0) {\n    throw new BadRequestError('Path must not be empty');\n  }","sourceCodeStart":44,"sourceCodeEnd":80,"githubUrl":"https://github.com/abhigyanpatwari/GitNexus/blob/aac7515d2a8c50a1f8f923c6fb77218b333560d6/gitnexus/src/server/validation.ts#L44-L80","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"// before\nfetch('/api/search?name[user]=1');   // nested object → 400\nfetch('/api/search', { body: JSON.stringify({ name: 42 }) });\n\n// after\nfetch('/api/search?name=foo');\nfetch('/api/search', { body: JSON.stringify({ name: 'foo' }) });","handlingStrategy":"type-guard","validationCode":"const body = { name: String(rawName ?? '') };\nif (!body.name) throw new Error('name must be a non-empty string');","typeGuard":"function isStringParam(v: unknown): v is string {\n  return typeof v === 'string';\n}","tryCatchPattern":null,"preventionTips":["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"],"tags":["validation","express","type-confusion","http-400"],"backgroundTag":"parameter-validation-failed","analyzedSha":"aac7515d2a8c50a1f8f923c6fb77218b333560d6","analyzedAt":"2026-08-20T23:29:22.980Z","schemaVersion":2},"datasetVersion":"2026-08-22T14:17:55.899Z"}