{"record":{"id":"eb5d09f99cc6a2d0","repo":"abhigyanpatwari/GitNexus","slug":"upload-failed","errorCode":null,"errorMessage":"Upload failed","messagePattern":"Upload failed","errorType":"http","errorClass":null,"httpStatus":500,"severity":"error","filePath":"gitnexus/src/server/analyze-upload.ts","lineNumber":152,"sourceCode":"\n      res.status(202).json({ jobId: job.id, status: job.status });\n    } catch (err) {\n      // Release the single analysis slot if a job was created but never\n      // launched — otherwise the leaked queued job blocks all future analyses.\n      if (createdJobId && !launched) {\n        deps.failJob(createdJobId, err instanceof Error ? err.message : 'Upload failed');\n      }\n      if (stageRoot) {\n        await fsp.rm(stageRoot, { recursive: true, force: true }).catch(() => {});\n      }\n      if (promotedDir && !launched) {\n        await fsp.rm(promotedDir, { recursive: true, force: true }).catch(() => {});\n      }\n      if (err instanceof BadRequestError) {\n        res.status(err.status).json({ error: err.message });\n        return;\n      }\n      res.status(500).json({ error: 'Upload failed' });\n    }\n  };\n}\n","sourceCodeStart":134,"sourceCodeEnd":156,"githubUrl":"https://github.com/abhigyanpatwari/GitNexus/blob/aac7515d2a8c50a1f8f923c6fb77218b333560d6/gitnexus/src/server/analyze-upload.ts#L134-L156","documentation":"Generic HTTP 500 from POST of a folder upload (analyze-upload handler) when something failed that is not a BadRequestError. The handler streams a multipart upload to a staging dir, validates it is a folder, occupies the single analysis slot via createJob (409 if busy), promotes staging with an atomic rename, removes any carried .gitnexus index, and launches analysis. All expected client mistakes (no usable name, upload not a folder, 409 already-in-progress) surface as their own 4xx via BadRequestError; this 500 means an infrastructure-level failure — the upload stream broke, or a filesystem operation (mkdir/rename under UPLOAD_ROOT) failed. The catch also releases the job slot and deletes staging/promoted dirs, so retries start clean.","triggerScenarios":"Network interruption mid-multipart-upload making ingest throw; disk full or permission denied when creating UPLOAD_ROOT or renaming stageRoot/<topLevelName> to the final dir; the deps.launch step throwing before the 202 is sent; busboy/parser errors on a truncated request body.","commonSituations":"Uploading very large folders over flaky connections; UPLOAD_ROOT on a volume that is full or read-only; a server-side path change between staging and final location; reverse proxy cutting off long uploads at a timeout (nginx client_max_body_size / proxy_read_timeout).","solutions":["Check the server stderr/log for the original exception — the 500 envelope deliberately hides it","Verify the client is uploading a folder (multipart with webkitRelativePath entries, one top-level directory), since the 400 'Upload must be a folder' path covers only the cleanly-detected case","Confirm UPLOAD_ROOT is writable and the volume has free space; check reverse-proxy body-size and timeout limits for large uploads","Retry the upload — the handler cleans up staging and releases the analysis slot on failure, so a retry is always safe"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"// Validate the folder selection before starting the upload.\nfunction assertFolderUpload(files: File[]): void {\n  const roots = new Set(files.map((f) => (f as File & { webkitRelativePath?: string }).webkitRelativePath?.split('/')[0] ?? ''));\n  if (roots.size === 0 || roots.has('')) throw new Error('select a folder (webkitdirectory), not loose files');\n}","typeGuard":null,"tryCatchPattern":"try {\n  const res = await uploadFolder(form);\n  if (res.status === 500 && (await res.json()).error === 'Upload failed') {\n    showTransientError('Upload failed server-side — check server logs; your slot was released, safe to retry');\n    return retryUploadOnce();\n  }\n  if (res.status === 409) { await waitForActiveJob(); return uploadFolder(form); } // never auto-spam 409\n  return res;\n} catch (e) {\n  reportUploadError(e); // network interruption mid-multipart also lands here client-side\n}","preventionTips":["Upload folders only (multipart entries with webkitRelativePath under one top-level dir)","Keep an eye on server disk space and UPLOAD_ROOT writability","Size reverse-proxy body limits and timeouts for your largest repos","Handle 409 (analysis in progress) with polling, not immediate retries"],"tags":["upload","multipart","http-500","filesystem"],"backgroundTag":"file-upload-failed","analyzedSha":"aac7515d2a8c50a1f8f923c6fb77218b333560d6","analyzedAt":"2026-08-20T23:29:22.980Z","schemaVersion":2},"datasetVersion":"2026-08-22T14:17:55.899Z"}