danny-avila/LibreChat · error

Unexpected batch upload response: ${JSON.stringify(result).s

Error message

Unexpected batch upload response: ${JSON.stringify(result).slice(0, 200)}

What it means

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.

Source

Thrown at api/server/services/Files/Code/crud.js:255

    },
    httpAgent: codeServerHttpAgent,
    httpsAgent: codeServerHttpsAgent,
    timeout: 120000,
    maxContentLength: MAX_FILE_SIZE,
    maxBodyLength: MAX_FILE_SIZE,
  };

  const response = await axios.post(`${baseURL}/upload/batch`, form, options);

  /** @type {{ message: string; storage_session_id: string; files: Array<{ status: string; fileId?: string; filename: string; error?: string }>; succeeded: number; failed: number }} */
  const result = response.data;
  if (
    !result ||
    typeof result !== 'object' ||
    !result.storage_session_id ||
    !Array.isArray(result.files)
  ) {
    throw new Error(`Unexpected batch upload response: ${JSON.stringify(result).slice(0, 200)}`);
  }
  if (result.message === 'error') {
    throw new Error('All files in batch upload failed');
  }

  if (result.failed > 0) {
    const failedNames = result.files
      .filter((f) => f.status === 'error')
      .map((f) => `${f.filename}: ${f.error || 'unknown'}`)
      .join(', ');
    logger.warn(`[batchUploadCodeEnvFiles] ${result.failed} file(s) failed: ${failedNames}`);
  }

  const successFiles = result.files
    .filter((f) => f.status === 'success' && f.fileId)
    .map((f) => ({ fileId: f.fileId, filename: f.filename }));

  return { storage_session_id: result.storage_session_id, files: successFiles };

View on GitHub (pinned to 5ff282f900)

Solutions

  1. Capture the first 200 chars of the response (the error message already truncates to 200) to see what codeapi actually returned.
  2. Confirm the code server version supports the /upload/batch endpoint and its documented response shape.
  3. Check for an intercepting proxy (nginx, ingress) that may have returned an HTML error page.
  4. Fall back to per-file uploads if the batch endpoint is unavailable on this deployment.
Defensive patterns

Strategy: fallback

Type guard

/** @param {unknown} r * @returns {r is { storage_session_id: string; files: unknown[] }} */
function isBatchUploadResponse(r) {
  return !!r && typeof r === 'object' && typeof r.storage_session_id === 'string' && Array.isArray(r.files);
}

Try / catch

try {
  await batchUploadCodeEnvFiles(params);
} catch (err) {
  if (/Unexpected batch upload response/.test(err.message)) {
    // fall back to per-file uploads
    return Promise.all(files.map((f) => uploadCodeEnvFile({ ...params, file: f })));
  }
  throw err;
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of danny-avila/LibreChat@5ff282f900 (2026-08-12). Data as JSON: /api/errors/bc3155c235ea69eb. Report an issue: GitHub.