{"record":{"id":"a6889cbc4815474c","repo":"Budibase/budibase","slug":"file-id-not-found","errorCode":null,"errorMessage":"File id not found","messagePattern":"File id not found","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/server/src/sdk/workspace/ai/llm/bbai.ts","lineNumber":258,"sourceCode":"        formdata.append(\"file\", fileBlob, filename)\n        formdata.append(\"model\", model)\n\n        const liteLLMBaseUrl = environment.LITELLM_URL.replace(/\\/v1\\/?$/, \"\")\n        const response = await fetch(`${liteLLMBaseUrl}/v1/files`, {\n          method: \"POST\",\n          headers: {\n            Authorization: `Bearer ${getBBAIKey()}`,\n          },\n          body: formdata,\n        })\n\n        if (!response.ok) {\n          throw await HTTPError.fromResponse(response)\n        }\n\n        const result = await response.json()\n        if (typeof result.id !== \"string\") {\n          throw new Error(\"File id not found\")\n        }\n        return unwrapLiteLLMFileId(result.id)\n      } else {\n        const fileBuffer = Buffer.from(await fileBlob.arrayBuffer())\n        const base64 = fileBuffer.toString(\"base64\")\n\n        if (isImage) {\n          return `data:${type};base64,${base64}`\n        }\n        if (!env.BUDICLOUD_URL) {\n          throw new Error(\"No Budibase URL found\")\n        }\n        const licenseKey = await licensing.keys.getLicenseKey()\n        if (!licenseKey) {\n          throw new Error(\"No license key found\")\n        }\n\n        const response = await fetch(","sourceCodeStart":240,"sourceCodeEnd":276,"githubUrl":"https://github.com/Budibase/budibase/blob/a81a902e9a8fe55b467d106765f6638f12e35c49/packages/server/src/sdk/workspace/ai/llm/bbai.ts#L240-L276","documentation":"Thrown during LiteLLM file upload when the /v1/files response JSON parses successfully but has no string `id` field. Budibase needs the LiteLLM file id to reference the uploaded file in subsequent chat calls, so an unexpected response shape is rejected with this error.","triggerScenarios":"Uploading a file via createBBAIClient's LiteLLM path when LiteLLM returns an error payload (e.g. a JSON error body with HTTP 200, or a proxy returning HTML/JSON without id), or a LiteLLM version whose files API response schema differs.","commonSituations":"LiteLLM behind a misconfigured proxy that intercepts file uploads; LiteLLM deployed at an older version without OpenAI-compatible /v1/files support; provider upstream rejecting the file but LiteLLM not propagating the failure status.","solutions":["Log/inspect the full LiteLLM /v1/files response body to see the actual payload","Upgrade LiteLLM to a version with OpenAI-compatible file upload support","Verify LITELLM_URL points at the LiteLLM proxy root, not a provider directly","Check LiteLLM proxy logs for upstream provider errors swallowed during upload"],"exampleFix":"// before: blind cast\nconst result = await response.json()\nreturn result.id\n// after: guard the shape\nconst result = await response.json()\nif (typeof result.id !== \"string\") {\n  throw new Error(`Unexpected LiteLLM file upload response: ${JSON.stringify(result)}`)\n}","handlingStrategy":"type-guard","validationCode":"const res = await fetch(`${litellmUrl}/v1/files`, init)\nconst body = await res.json()\nif (typeof body?.id !== \"string\") {\n  throw new Error(`LiteLLM upload returned unexpected payload`)\n}","typeGuard":"function hasFileId(x: unknown): x is { id: string } {\n  return typeof x === \"object\" && x !== null && typeof (x as { id?: unknown }).id === \"string\"\n}","tryCatchPattern":"try {\n  const id = await bbaiClient.uploadFile(blob, type)\n} catch (e) {\n  if (e.message === \"File id not found\") {\n    log.error(\"LiteLLM file upload returned malformed response — check LiteLLM version/proxy\")\n  }\n  throw e\n}","preventionTips":["Pin a LiteLLM version known to support OpenAI-compatible /v1/files","Point LITELLM_URL at the LiteLLM proxy, not a raw provider","Add an integration smoke test that uploads a tiny file on deploy"],"tags":["litellm","file-upload","api-response","budibase-ai"],"backgroundTag":"unexpected-api-response-shape","analyzedSha":"a81a902e9a8fe55b467d106765f6638f12e35c49","analyzedAt":"2026-08-29T01:03:10.972Z","schemaVersion":2},"datasetVersion":"2026-08-29T02:17:18.158Z"}