{"record":{"id":"bc3155c235ea69eb","repo":"danny-avila/LibreChat","slug":"unexpected-batch-upload-response-json-stringify","errorCode":null,"errorMessage":"Unexpected batch upload response: ${JSON.stringify(result).slice(0, 200)}","messagePattern":"Unexpected batch upload response: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"api/server/services/Files/Code/crud.js","lineNumber":255,"sourceCode":"    },\n    httpAgent: codeServerHttpAgent,\n    httpsAgent: codeServerHttpsAgent,\n    timeout: 120000,\n    maxContentLength: MAX_FILE_SIZE,\n    maxBodyLength: MAX_FILE_SIZE,\n  };\n\n  const response = await axios.post(`${baseURL}/upload/batch`, form, options);\n\n  /** @type {{ message: string; storage_session_id: string; files: Array<{ status: string; fileId?: string; filename: string; error?: string }>; succeeded: number; failed: number }} */\n  const result = response.data;\n  if (\n    !result ||\n    typeof result !== 'object' ||\n    !result.storage_session_id ||\n    !Array.isArray(result.files)\n  ) {\n    throw new Error(`Unexpected batch upload response: ${JSON.stringify(result).slice(0, 200)}`);\n  }\n  if (result.message === 'error') {\n    throw new Error('All files in batch upload failed');\n  }\n\n  if (result.failed > 0) {\n    const failedNames = result.files\n      .filter((f) => f.status === 'error')\n      .map((f) => `${f.filename}: ${f.error || 'unknown'}`)\n      .join(', ');\n    logger.warn(`[batchUploadCodeEnvFiles] ${result.failed} file(s) failed: ${failedNames}`);\n  }\n\n  const successFiles = result.files\n    .filter((f) => f.status === 'success' && f.fileId)\n    .map((f) => ({ fileId: f.fileId, filename: f.filename }));\n\n  return { storage_session_id: result.storage_session_id, files: successFiles };","sourceCodeStart":237,"sourceCodeEnd":273,"githubUrl":"https://github.com/danny-avila/LibreChat/blob/5ff282f9006c436e561de1afd39a481bea1ef0d8/api/server/services/Files/Code/crud.js#L237-L273","documentation":"Thrown by batchUploadCodeEnvFiles (Code/crud.js) when the codeapi POST /upload/batch response is structurally invalid: missing storage_session_id, missing files array, or not an object. This is a contract-mismatch guard, not a per-file failure.","triggerScenarios":"codeapi returns a response that breaks the documented `{ message, storage_session_id, files[], succeeded, failed }` shape — e.g. an HTML error page parsed as a string, a 2xx with an error body, or a newer/older API version with a different schema.","commonSituations":"Code server version skew (response schema changed); code server behind a reverse proxy returning an HTML 502; auth passed but the batch endpoint isn't enabled on this build.","solutions":["Capture the first 200 chars of the response (the error message already truncates to 200) to see what codeapi actually returned.","Confirm the code server version supports the /upload/batch endpoint and its documented response shape.","Check for an intercepting proxy (nginx, ingress) that may have returned an HTML error page.","Fall back to per-file uploads if the batch endpoint is unavailable on this deployment."],"exampleFix":null,"handlingStrategy":"fallback","validationCode":null,"typeGuard":"/** @param {unknown} r * @returns {r is { storage_session_id: string; files: unknown[] }} */\nfunction isBatchUploadResponse(r) {\n  return !!r && typeof r === 'object' && typeof r.storage_session_id === 'string' && Array.isArray(r.files);\n}","tryCatchPattern":"try {\n  await batchUploadCodeEnvFiles(params);\n} catch (err) {\n  if (/Unexpected batch upload response/.test(err.message)) {\n    // fall back to per-file uploads\n    return Promise.all(files.map((f) => uploadCodeEnvFile({ ...params, file: f })));\n  }\n  throw err;\n}","preventionTips":["Type-guard the batch response before consuming it.","Fall back to per-file uploads when the batch endpoint is unavailable or returns a foreign shape.","Keep codeapi version in sync with the documented batch response contract."],"tags":["code-env","upload","batch","contract","validation"],"backgroundTag":null,"analyzedSha":"5ff282f9006c436e561de1afd39a481bea1ef0d8","analyzedAt":"2026-08-12T21:38:08.145Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}