{"record":{"id":"643eb425be4ec9e9","repo":"Significant-Gravitas/AutoGPT","slug":"authentication-error-please-sign-in-again","errorCode":null,"errorMessage":"Authentication error — please sign in again.","messagePattern":"Authentication error — please sign in again\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"autogpt_platform/frontend/src/lib/direct-upload.ts","lineNumber":78,"sourceCode":"    variant: \"destructive\",\n  });\n  return true;\n}\n\ninterface DirectUploadArgs {\n  path: string;\n  file: File;\n  searchParams?: Record<string, string>;\n}\n\nasync function postFileToBackend({\n  path,\n  file,\n  searchParams,\n}: DirectUploadArgs): Promise<Response> {\n  const { token, error: tokenError } = await getWebSocketToken();\n  if (tokenError || !token) {\n    throw new Error(\"Authentication error — please sign in again.\");\n  }\n\n  const baseURL = new URL(environment.getAGPTServerBaseUrl());\n  baseURL.pathname = `${baseURL.pathname.replace(/\\/$/, \"\")}/${path.replace(/^\\//, \"\")}`;\n  const url = baseURL;\n  for (const [key, value] of Object.entries(searchParams ?? {})) {\n    url.searchParams.set(key, value);\n  }\n\n  const formData = new FormData();\n  formData.append(\"file\", file);\n\n  return fetch(url.toString(), {\n    method: \"POST\",\n    headers: { Authorization: `Bearer ${token}` },\n    body: formData,\n    // Guard against a stalled connection leaving the UI stuck \"Uploading…\".\n    // Generous so large (up to 50MB) uploads on slow links aren't cut off.","sourceCodeStart":60,"sourceCodeEnd":96,"githubUrl":"https://github.com/Significant-Gravitas/AutoGPT/blob/9c8bb5550f446ba5d3046b78896578742495b3cf/autogpt_platform/frontend/src/lib/direct-upload.ts#L60-L96","documentation":"Thrown by postFileToBackend in src/lib/direct-upload.ts when getWebSocketToken() returns an error or no token. This helper supplies the Authorization header for direct file uploads to the backend (bypassing the Next.js proxy), so without a valid JWT the upload is aborted before it starts. Functionally identical to the copilot auth error (error 20) — same token source, same failure class — but for upload endpoints.","triggerScenarios":"Uploading a file (block media upload, store thumbnails, etc.) with an expired Supabase session, a missing session cookie, or a failed getWebSocketToken server action (backend/auth misconfiguration or network failure).","commonSituations":"Long-open builder tab past JWT expiry; signed out in another tab; dev environment with mismatched Supabase config; cookies blocked by browser settings so the server action can't authenticate.","solutions":["Sign in again (reload the app) — simplest and correct for expired sessions.","Verify the getWebSocketToken server action call in DevTools; non-200 there points at Supabase config, not the upload endpoint.","Check NEXT_PUBLIC_SUPABASE_* env vars in frontend/.env for the usual dev drift.","Harden callers to catch this and trigger re-auth/redirect instead of surfacing a raw upload failure."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"import { getWebSocketToken } from \"@/lib/auth/actions\";\n\nasync function assertUploadAuth(): Promise<string> {\n  const { token, error } = await getWebSocketToken();\n  if (error || !token) throw new Error(\"Authentication error — please sign in again.\");\n  return token;\n}","typeGuard":"function isUploadAuthError(err: unknown): boolean {\n  return err instanceof Error && err.message.startsWith(\"Authentication error\");\n}","tryCatchPattern":"try {\n  await postFileToBackend({ path, file });\n} catch (error) {\n  if (isUploadAuthError(error)) {\n    window.location.href = \"/login\"; // no point retrying with a dead session\n    return;\n  }\n  throw error;\n}","preventionTips":["Fetch a fresh token per upload rather than reusing one captured at page load.","Catch this error at the upload UI layer and redirect to sign-in; a toast alone strands the user.","Use the same auth-header helper pattern everywhere so expired sessions fail uniformly."],"tags":["authentication","upload","supabase","session-expiry","frontend"],"backgroundTag":null,"analyzedSha":"9c8bb5550f446ba5d3046b78896578742495b3cf","analyzedAt":"2026-08-14T17:17:21.957Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}