{"record":{"id":"5a4f1895a0cf22b7","repo":"abhigyanpatwari/GitNexus","slug":"path-must-be-a-string","errorCode":null,"errorMessage":"\"path\" must be a string","messagePattern":"\"path\" must be a string","errorType":"http","errorClass":null,"httpStatus":400,"severity":"error","filePath":"gitnexus/src/server/api.ts","lineNumber":1510,"sourceCode":"    requireTrustedOrigin,\n    async (req, res) => {\n      try {\n        const {\n          url: repoUrl,\n          path: repoLocalPath,\n          force,\n          embeddings,\n          dropEmbeddings,\n          token: repoToken,\n        } = req.body;\n\n        // Input type validation\n        if (repoUrl !== undefined && typeof repoUrl !== 'string') {\n          res.status(400).json({ error: '\"url\" must be a string' });\n          return;\n        }\n        if (repoLocalPath !== undefined && typeof repoLocalPath !== 'string') {\n          res.status(400).json({ error: '\"path\" must be a string' });\n          return;\n        }\n\n        if (!repoUrl && !repoLocalPath) {\n          res.status(400).json({ error: 'Provide \"url\" (git URL) or \"path\" (local path)' });\n          return;\n        }\n\n        // Token: optional, restricted charset to prevent header smuggling\n        // (CRLF), bound length, and bound to github.com (see validateAnalyzeToken).\n        const tokenError = validateAnalyzeToken(repoToken, repoUrl);\n        if (tokenError) {\n          res.status(tokenError.status).json({ error: tokenError.error });\n          return;\n        }\n\n        // Path validation. The previous `normalize !== resolve` guard was inert\n        // (both collapse `..` identically) and only false-rejected trailing","sourceCodeStart":1492,"sourceCodeEnd":1528,"githubUrl":"https://github.com/abhigyanpatwari/GitNexus/blob/aac7515d2a8c50a1f8f923c6fb77218b333560d6/gitnexus/src/server/api.ts#L1492-L1528","documentation":"HTTP 400 returned by POST /api/analyze when the JSON body contains a \"path\" field whose value is not a string. The route destructures { url, path, force, embeddings, dropEmbeddings, token } from req.body and type-checks each optional field before creating a job, because the path value flows straight into the analysis worker as a filesystem location.","triggerScenarios":"POST /api/analyze with {\"path\": null}, {\"path\": 42}, {\"path\": [\"/repos/foo\"]} or {\"path\": {\"dir\": \"/repos/foo\"}} — e.g. a directory picker returning an entries array, or a whole config object being sent where one of its string fields was intended.","commonSituations":"Browser/Electron folder pickers returning entry lists; YAML/env configs parsed into objects; serializers emitting null for undefined; URLSearchParams-style encoders producing arrays for scalar fields.","solutions":["Send path as one JSON string, e.g. {\"path\": \"/home/me/repos/foo\"}","Pick the string out of structured picker results (entries[0].fullPath), not the array or object","Omit the key when there is no local path rather than sending null","Double-check the Content-Type is application/json so the body is actually parsed"],"exampleFix":"// before\nconst body = { path: dirPicker.entries }; // array of picked entries\n\n// after\nconst body = { path: dirPicker.entries[0].fullPath }; // single absolute path string","handlingStrategy":"validation","validationCode":"// Run before POSTing to /api/analyze\nif ('path' in body && typeof body.path !== 'string') {\n  throw new TypeError(`\"path\" must be a string, got ${typeof body.path}`);\n}","typeGuard":"const isMaybeString = (v: unknown): v is string | undefined =>\n  v === undefined || typeof v === 'string';","tryCatchPattern":"On 400, inspect res.body.error — a type failure is deterministic per payload; correct the field (or omit it) before re-sending.","preventionTips":["Extract scalar strings from picker/config results before serializing","Never send null for optional fields on this route","Assert field types in a shared request-builder used by UI and tests"],"tags":["http-400","validation","request-body","filesystem","api"],"backgroundTag":"request-body-validation","analyzedSha":"aac7515d2a8c50a1f8f923c6fb77218b333560d6","analyzedAt":"2026-08-20T23:29:22.980Z","schemaVersion":2},"datasetVersion":"2026-08-22T14:17:55.899Z"}