{"record":{"id":"dcf6c9819f60f1bc","repo":"abhigyanpatwari/GitNexus","slug":"missing-cypher-in-request-body","errorCode":null,"errorMessage":"Missing \"cypher\" in request body","messagePattern":"Missing \"cypher\" in request body","errorType":"http","errorClass":null,"httpStatus":400,"severity":"error","filePath":"gitnexus/src/server/api.ts","lineNumber":651,"sourceCode":"      res.status(404).json({ error: 'File not found' });\n    } else {\n      // statusFromError returns err.status for BadRequestError / ForbiddenError\n      // (assertString → 400 on array-form ?path=a&path=b; ForbiddenError → 403\n      // on traversal). Falls back to 500 for unrecognized failures.\n      res.status(statusFromError(err)).json({ error: err.message || 'Failed to read file' });\n    }\n  }\n};\n\nexport const handleQueryRequest = async (\n  req: express.Request,\n  res: express.Response,\n  resolveRepo: (repoName?: string) => Promise<{ storagePath: string } | undefined>,\n): Promise<void> => {\n  try {\n    const cypher = req.body.cypher as string;\n    if (!cypher) {\n      res.status(400).json({ error: 'Missing \"cypher\" in request body' });\n      return;\n    }\n    const queryParams = req.body.params;\n    if (queryParams !== undefined && !isValidQueryParams(queryParams)) {\n      res.status(400).json({\n        error: '\"params\" must be a plain object with scalar values (string/number/boolean/null)',\n      });\n      return;\n    }\n\n    const entry = await resolveRepo(requestedRepo(req));\n    if (!entry) {\n      res.status(404).json({ error: 'Repository not found' });\n      return;\n    }\n    const lbugPath = path.join(entry.storagePath, 'lbug');\n    const result = await withLbugDb(lbugPath, () => executePrepared(cypher, queryParams ?? {}), {\n      readOnly: true,","sourceCodeStart":633,"sourceCodeEnd":669,"githubUrl":"https://github.com/abhigyanpatwari/GitNexus/blob/aac7515d2a8c50a1f8f923c6fb77218b333560d6/gitnexus/src/server/api.ts#L633-L669","documentation":"HTTP 400 from POST /api/query when req.body.cypher is falsy — undefined, null, or the empty string. The query endpoint requires a JSON body with a non-empty cypher string before it will resolve a repository and open the read-only LadybugDB connection. If instead you see a 500 with a TypeError message, your body was never parsed (missing Content-Type: application/json) — a different failure that this 400 is designed to preempt.","triggerScenarios":"POSTing {} or {query: 'MATCH ...'} (wrong key — the key must be exactly cypher); sending cypher: '' for a 'run nothing' call; omitting the Content-Type header so express.json skips parsing and req.body stays unset; sending form-encoded instead of JSON.","commonSituations":"Copy-pasting a client for the /api/grep endpoint and forgetting the query API uses a different body key; API explorers defaulting to text/plain content type; code paths that build the body conditionally and skip the cypher field when a template is empty.","solutions":["Send JSON with the exact key: {\"cypher\": \"MATCH (n) RETURN n LIMIT 5\"} and header Content-Type: application/json","Client-side, assert a non-empty string before issuing the request","If you got a 500 mentioning 'cypher of undefined', your body was not parsed — set the content type","Pass query values via the optional params object rather than string interpolation"],"exampleFix":"// before\nawait fetch(`${base}/api/query`, {\n  method: 'POST',\n  body: JSON.stringify({ query }), // wrong key → 400\n});\n\n// after\nawait fetch(`${base}/api/query`, {\n  method: 'POST',\n  headers: { 'content-type': 'application/json' },\n  body: JSON.stringify({ cypher: query, params: { limit: 5 } }),\n});","handlingStrategy":"validation","validationCode":"if (typeof cypher !== 'string' || cypher.trim() === '') throw new Error('cypher body field is required');\nawait fetch(`${base}/api/query`, { method: 'POST', headers: { 'content-type': 'application/json' }, body: JSON.stringify({ cypher }) });","typeGuard":"function isQueryBody(b: unknown): b is { cypher: string; params?: Record<string, string | number | boolean | null> } {\n  if (typeof b !== 'object' || b === null) return false;\n  const c = (b as Record<string, unknown>).cypher;\n  return typeof c === 'string' && c.length > 0;\n}","tryCatchPattern":null,"preventionTips":["Use the exact body key 'cypher' (not query/statement)","Set Content-Type: application/json so express.json actually parses the body","Guard against empty templates producing cypher: ''"],"tags":["http-400","api","cypher","request-body","validation"],"backgroundTag":"missing-required-parameter","analyzedSha":"aac7515d2a8c50a1f8f923c6fb77218b333560d6","analyzedAt":"2026-08-20T23:29:22.980Z","schemaVersion":2},"datasetVersion":"2026-08-22T14:17:55.899Z"}