{"record":{"id":"b89ed45d3967d91b","repo":"Mintplex-Labs/anything-llm","slug":"failed-to-fetch-logo","errorCode":null,"errorMessage":"Failed to fetch logo!","messagePattern":"Failed to fetch logo!","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"warning","filePath":"frontend/src/models/system.js","lineNumber":481,"sourceCode":"  fetchLogo: async function () {\n    const url = new URL(`${fullApiUrl()}/system/logo`);\n    url.searchParams.append(\n      \"theme\",\n      localStorage.getItem(\"theme\") || \"default\"\n    );\n\n    return await fetch(url, {\n      method: \"GET\",\n      cache: \"no-cache\",\n    })\n      .then(async (res) => {\n        if (res.ok && res.status !== 204) {\n          const isCustomLogo = res.headers.get(\"X-Is-Custom-Logo\") === \"true\";\n          const blob = await res.blob();\n          const logoURL = URL.createObjectURL(blob);\n          return { isCustomLogo, logoURL };\n        }\n        throw new Error(\"Failed to fetch logo!\");\n      })\n      .catch((e) => {\n        console.log(e);\n        return { isCustomLogo: false, logoURL: null };\n      });\n  },\n  fetchPfp: async function (id) {\n    return await fetch(`${API_BASE}/system/pfp/${id}`, {\n      method: \"GET\",\n      cache: \"no-cache\",\n      headers: baseHeaders(),\n    })\n      .then((res) => {\n        if (res.ok && res.status !== 204) return res.blob();\n        throw new Error(\"Failed to fetch pfp.\");\n      })\n      .then((blob) => (blob ? URL.createObjectURL(blob) : null))\n      .catch(() => {","sourceCodeStart":463,"sourceCodeEnd":499,"githubUrl":"https://github.com/Mintplex-Labs/anything-llm/blob/526360e320da9d1b36074be5ed64fe76e5bbfbbd/frontend/src/models/system.js#L463-L499","documentation":"Thrown by System.fetchLogo when the GET to {fullApiUrl()}/system/logo?theme=... returns a non-2xx status OR returns 204 No Content. Notably this route sends NO auth headers (it must render on the login screen) and uses fullApiUrl() (absolute). The .catch() returns {isCustomLogo:false, logoURL:null}, so failure silently falls back to the default logo.","triggerScenarios":"Calling fetchLogo() when the logo file is missing on disk (404), when the server returns 204 (no custom logo set — treated as an error here), when fullApiUrl() points at the wrong origin (CORS), or when the theme param is invalid.","commonSituations":"A 204 response from a deployment with no custom logo — this is actually a normal state but is treated as an error; fullApiUrl() resolves to a host that does not serve /system/logo; reverse proxy strips the theme query param.","solutions":["Treat 204 as 'no custom logo' rather than an error — the guard conflates the two.","Confirm fullApiUrl() returns the same origin that serves the /api routes.","Check the server's logo storage path for a custom file.","Ensure the reverse proxy preserves the ?theme= query string."],"exampleFix":"// before\nif (res.ok && res.status !== 204) { ... }\nthrow new Error(\"Failed to fetch logo!\");\n\n// after (204 is not an error)\nif (res.status === 204) return { isCustomLogo: false, logoURL: null };\nif (!res.ok) throw new Error(`Failed to fetch logo! (${res.status})`);","handlingStrategy":"fallback","validationCode":"// No auth header is sent; ensure fullApiUrl() origin serves /system/logo.\nfunction sameOriginLogoUrl() {\n  try { return new URL(fullApiUrl()).origin === window.location.origin; }\n  catch { return false; }\n}","typeGuard":"/** @param {any} r @returns {r is {isCustomLogo:boolean, logoURL:string|null}} */\nfunction isLogoResult(r) {\n  return r != null && typeof r.isCustomLogo === \"boolean\" && (r.logoURL === null || typeof r.logoURL === \"string\");\n}","tryCatchPattern":"const res = await System.fetchLogo();\nif (!isLogoResult(res) || !res.logoURL) { renderDefaultLogo(); }","preventionTips":["Treat a 204 (no custom logo) as a normal state, not an error.","Confirm fullApiUrl() resolves to the serving origin.","Always have a default-logo fallback ready in the UI."],"tags":["network","branding","logo","cors"],"backgroundTag":null,"analyzedSha":"526360e320da9d1b36074be5ed64fe76e5bbfbbd","analyzedAt":"2026-08-13T01:45:47.170Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}