{"record":{"id":"e4d83b8465dee1e2","repo":"Mintplex-Labs/anything-llm","slug":"text","errorCode":null,"errorMessage":"text","messagePattern":"text","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"frontend/src/models/system.js","lineNumber":818,"sourceCode":"      this.cacheKeys.canViewChatHistory,\n      JSON.stringify({ viewable: isViewable, lastFetched: Date.now() })\n    );\n    return { viewable: isViewable, error: null };\n  },\n\n  /**\n   * Validates a temporary auth token and logs in the user if the token is valid.\n   * @param {string} publicToken - the token to validate against\n   * @returns {Promise<{valid: boolean, user: import(\"@prisma/client\").users | null, token: string | null, message: string | null}>}\n   */\n  simpleSSOLogin: async function (publicToken) {\n    return fetch(`${API_BASE}/request-token/sso/simple?token=${publicToken}`, {\n      method: \"GET\",\n    })\n      .then(async (res) => {\n        if (!res.ok) {\n          const text = await res.text();\n          if (!text.startsWith(\"{\")) throw new Error(text);\n          return JSON.parse(text);\n        }\n        return await res.json();\n      })\n      .catch((e) => {\n        console.error(e);\n        return { valid: false, user: null, token: null, message: e.message };\n      });\n  },\n\n  /**\n   * Fetches the app version from the server.\n   * @returns {Promise<string | null>} The app version.\n   */\n  fetchAppVersion: async function () {\n    const cache = window.localStorage.getItem(this.cacheKeys.deploymentVersion);\n    const { version, lastFetched } = cache\n      ? safeJsonParse(cache, { version: null, lastFetched: 0 })","sourceCodeStart":800,"sourceCodeEnd":836,"githubUrl":"https://github.com/Mintplex-Labs/anything-llm/blob/20f6d3546c1938bfea1ad304f58a592dddcc5948/frontend/src/models/system.js#L800-L836","documentation":"Thrown by simpleSSOLogin in the AnythingLLM frontend when GET /api/request-token/sso/simple?token=... responds non-2xx and the body is NOT JSON (does not start with '{'). The raw body text becomes the Error message — so when a reverse proxy returns an HTML 502/504 page, the 'message' is an entire HTML document. If the body is JSON it is parsed and returned as a structured { valid:false, message } payload instead, never throwing.","triggerScenarios":"Authenticating with an invalid, expired, or already-consumed single-use SSO token (server replies plain-text error); simple SSO not enabled server-side; the app is down behind nginx/traefik and the proxy's HTML error page is returned; token truncated or padded with whitespace when copy-pasted.","commonSituations":"SSO links older than their TTL; email/chat clients breaking the URL across lines; app container restarting while the user clicks the link; gateway misrouting /api paths.","solutions":["Generate and use a fresh SSO link — tokens are single-use and short-lived.","Look at the message shape: HTML means infrastructure (proxy/app down), short plain text usually means the app rejected the token.","Confirm simple SSO is enabled on the server instance.","Copy the complete token with no truncation or surrounding whitespace."],"exampleFix":"// before\nif (!text.startsWith('{')) throw new Error(text); // whole HTML page becomes the message\n\n// after — keep only a clamped first line\nif (!text.startsWith('{')) {\n  const firstLine = text.trim().split('\\n')[0].slice(0, 200);\n  throw new Error(firstLine || `SSO login failed (${res.status})`);\n}","handlingStrategy":"try-catch","validationCode":"// run before System.simpleSSOLogin\nif (!publicToken || /\\s/.test(publicToken)) {\n  throw new Error('SSO token missing or contains whitespace');\n}","typeGuard":"/** @param {string} text @returns {text is string} */\nfunction isHtmlErrorBody(text) {\n  const t = text.trimStart().toLowerCase();\n  return t.startsWith('<!doctype') || t.startsWith('<html');\n}","tryCatchPattern":"const { valid, user, token, message } = await System.simpleSSOLogin(publicToken);\nif (!valid && isHtmlErrorBody(message || '')) {\n  showInfraError('Login gateway unavailable — try again later'); // proxy HTML page\n} else if (!valid) {\n  showLoginError(message || 'SSO token rejected');\n}","preventionTips":["Treat HTML-looking messages as infrastructure failures, not token failures.","Clamp displayed message length so a proxy error page cannot flood the UI.","Keep SSO links short-lived and single-use; never reuse one after success."],"tags":["anythingllm","sso","authentication","reverse-proxy","http"],"backgroundTag":"sso-token-invalid","analyzedSha":"20f6d3546c1938bfea1ad304f58a592dddcc5948","analyzedAt":"2026-08-18T10:02:21.017Z","contentChangedAt":"2026-08-18T10:02:21.017Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}