{"record":{"id":"64f0eaca6e9ec03d","repo":"langfuse/langfuse","slug":"failed-to-upload-attachments-to-pylon","errorCode":null,"errorMessage":"Failed to upload attachments to Pylon.","messagePattern":"Failed to upload attachments to Pylon\\.","errorType":"http","errorClass":"Error","httpStatus":null,"severity":"warning","filePath":"web/src/features/support-chat/SupportFormSection.tsx","lineNumber":286,"sourceCode":"        const base64 = btoa(\n          new Uint8Array(arrayBuffer).reduce(\n            (data, byte) => data + String.fromCharCode(byte),\n            \"\",\n          ),\n        );\n        return { fileName: file.name, fileBase64: base64 };\n      }),\n    );\n\n    const res = await fetch(\"/api/support/upload-attachments\", {\n      method: \"POST\",\n      headers: { \"Content-Type\": \"application/json\" },\n      body: JSON.stringify({ files: filePayloads }),\n    });\n\n    if (!res.ok) {\n      const body = await res.json().catch(() => ({}));\n      throw new Error(\n        (body as { error?: string }).error ??\n          \"Failed to upload attachments to Pylon.\",\n      );\n    }\n\n    const body = (await res.json()) as { attachment_urls: string[] };\n    return body.attachment_urls;\n  }\n\n  const onSubmit = async (values: SupportFormInput) => {\n    const parsed: SupportFormValues = SupportFormSchema.parse(values);\n    const msgLen = (parsed.message ?? \"\").trim().length;\n\n    if (msgLen < 50 && !warnedShortOnce) {\n      setWarnedShortOnce(true);\n      return;\n    }\n","sourceCodeStart":268,"sourceCodeEnd":304,"githubUrl":"https://github.com/langfuse/langfuse/blob/59d92c7cf365150d10b753b5a0d1708902a2ed60/web/src/features/support-chat/SupportFormSection.tsx#L268-L304","documentation":"The support-chat form uploads attachments to a Pylon endpoint; if the response is not ok and the response body contains no error field, this generic message is thrown. It means the upload HTTP request failed for some reason (auth, size limit, server error) without a structured error body.","triggerScenarios":"POSTing { files: [...] } to the Pylon upload route and receiving a non-2xx status with an unparseable or error-less body — e.g. 413 payload too large, 401/403 auth failure, 500 from Pylon, or a proxy/gateway (nginx, Cloudflare) returning an HTML error page that fails JSON parsing.","commonSituations":"Attaching files above the proxy or Pylon size limit; expired/missing session for the support chat; Pylon API outage or rate limit; Cloudflare 413/52x pages replacing the JSON error.","solutions":["Inspect the network tab for the actual status code and response body of the failed upload","Reduce attachment size/count and retry; compress screenshots before upload","Verify you are authenticated (session cookie present) when the support form loads","If a gateway/proxy error page is returned, raise its request body limit (e.g. nginx client_max_body_size)"],"exampleFix":"// before\nif (!res.ok) {\n  const body = await res.json().catch(() => ({}));\n  throw new Error((body as { error?: string }).error ?? \"Failed to upload attachments to Pylon.\");\n}\n\n// after\nif (!res.ok) {\n  const body = await res.json().catch(() => ({}));\n  throw new Error((body as { error?: string }).error ?? `Upload failed (HTTP ${res.status})`);\n}","handlingStrategy":"try-catch","validationCode":"const MAX_BYTES = 5 * 1024 * 1024;\nif (files.some((f) => f.size > MAX_BYTES)) {\n  setError(\"Each attachment must be under 5 MB.\");\n  return;\n}","typeGuard":"const isPylonUploadError = (err: unknown): boolean =>\n  err instanceof Error && /Pylon/i.test(err.message);","tryCatchPattern":"try {\n  await uploadFilesToPylon(files);\n} catch (err) {\n  if (err instanceof Error && err.message.includes(\"Pylon\")) {\n    setError(`Attachment upload failed: ${err.message}. Try smaller files or submit without attachments.`);\n    return; // allow form submit without attachments as fallback\n  }\n  throw err;\n}","preventionTips":["Show the HTTP status in the thrown message for diagnosis","Compress images client-side before upload","Make attachments optional so the support request can still be submitted on upload failure"],"tags":["support-chat","pylon","file-upload","http","frontend"],"backgroundTag":"http-request-failed","analyzedSha":"59d92c7cf365150d10b753b5a0d1708902a2ed60","analyzedAt":"2026-08-27T22:22:00.402Z","schemaVersion":2},"datasetVersion":"2026-08-28T00:17:15.603Z"}