{"record":{"id":"828fc553de5059d8","repo":"abhigyanpatwari/GitNexus","slug":"internal-server-error","errorCode":null,"errorMessage":"Internal server error","messagePattern":"Internal server error","errorType":"http","errorClass":null,"httpStatus":500,"severity":"critical","filePath":"gitnexus/src/server/api.ts","lineNumber":2047,"sourceCode":"    embedJobManager.cancelJob(jobId, 'Cancelled by user');\n    res.json({ id: job.id, status: 'failed', error: 'Cancelled by user' });\n  });\n\n  // ── Web UI (served at root) ───────────────────────────────────────\n\n  // Resolve the gitnexus-web dist directory relative to this file's location.\n  // In the published package: <pkg>/dist/server/api.js → <pkg>/web/\n  // In dev (tsx):            gitnexus/src/server/api.ts → gitnexus-web/dist/\n  const __dirname = path.dirname(fileURLToPath(import.meta.url));\n  const webDistDir = path.resolve(__dirname, '..', '..', 'web');\n  const devWebDistDir = path.resolve(__dirname, '..', '..', '..', 'gitnexus-web', 'dist');\n  const staticDir = await resolveWebDistDir(webDistDir, devWebDistDir);\n  registerWebUI(app, staticDir);\n\n  // Global error handler — catch anything the route handlers miss\n  app.use((err: any, _req: express.Request, res: express.Response, _next: express.NextFunction) => {\n    logger.error({ err }, 'Unhandled error:');\n    res.status(500).json({ error: 'Internal server error' });\n  });\n\n  // Wrap listen in a promise so errors (EADDRINUSE, EACCES, etc.) propagate\n  // to the caller instead of crashing with an unhandled 'error' event.\n  await new Promise<void>((resolve, reject) => {\n    const server = app.listen(port, host, () => {\n      const displayHost = host === '::' || host === '0.0.0.0' ? 'localhost' : host;\n      console.log(`GitNexus server running on http://${displayHost}:${port}`);\n      resolve();\n    });\n    server.on('error', (err) => reject(err));\n    // `listening` is the successful startup boundary for notifier work.\n    bindServeUpdateControllerLifecycle(server, updateController);\n\n    // Graceful shutdown — close Express + LadybugDB cleanly. Pino's default\n    // destination is `sync: false` (buffered); `flushLoggerSync()` before\n    // `process.exit` so records emitted during cleanup reach stderr.\n    const shutdown = async () => {","sourceCodeStart":2029,"sourceCodeEnd":2065,"githubUrl":"https://github.com/abhigyanpatwari/GitNexus/blob/0d1aed942f0e8b5d3bac27519fff441aceea722d/gitnexus/src/server/api.ts#L2029-L2065","documentation":"HTTP 500 emitted by the global Express error handler mounted after every route — the catch-all for exceptions route handlers and middleware did not absorb (notably express.json() parse failures, which this handler reports as 500 even though body-parser types them as 400). The real error is logged server-side as 'Unhandled error:' with the full object; the response body deliberately exposes no internals.","triggerScenarios":"Malformed JSON body (trailing commas, single quotes, unescaped newlines) reaching express.json(); an unexpected throw inside any route handler; middleware-level failures such as oversized or mis-declared bodies; errors re-thrown past a route's own try/catch.","commonSituations":"Hand-built request strings instead of JSON.stringify output; clients posting form-data to JSON-only endpoints; version-mismatch bugs; proxies mangling request bodies.","solutions":["Read the serve logs — the 'Unhandled error:' line has the stack; the client-visible body never will","Build bodies with JSON.stringify and send Content-Type: application/json","Retry once for potentially transient causes (races, broken streams); stop if the failure is deterministic","A deterministic reproduction reaching this handler is a server bug — update GitNexus and report it with the logged stack"],"exampleFix":"// before\nconst body = \"{'url': 'https://github.com/org/repo'}\"; // hand-written, invalid JSON\nawait fetch('/api/analyze', { method: 'POST', body });\n\n// after\nconst body = JSON.stringify({ url: 'https://github.com/org/repo' });\nawait fetch('/api/analyze', {\n  method: 'POST',\n  headers: { 'Content-Type': 'application/json' },\n  body,\n});","handlingStrategy":"retry","validationCode":"// Fail fast on hand-built JSON before sending\nfunction safeJsonParse(s: string): unknown {\n  try { return JSON.parse(s); } catch { throw new TypeError('Request body is not valid JSON'); }\n}","typeGuard":null,"tryCatchPattern":"Catch 500s at the fetch boundary: log the server-side correlation (timestamp + route), retry idempotent requests once with backoff, and report deterministic cases — the response body carries no diagnostic detail by design.","preventionTips":["Never hand-write JSON bodies — use JSON.stringify","Set Content-Type: application/json on all JSON endpoints","Watch the serve logs when debugging 500s; the response body is sanitized"],"tags":["http-500","express","global-error-handler","unhandled-exception","body-parser"],"backgroundTag":"unhandled-server-exception","analyzedSha":"0d1aed942f0e8b5d3bac27519fff441aceea722d","analyzedAt":"2026-08-20T23:29:22.980Z","contentChangedAt":"2026-08-20T23:29:22.980Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}