Mintplex-Labs/anything-llm · warning · Error

Failed to fetch logo!

Error message

Failed to fetch logo!

What it means

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.

Source

Thrown at frontend/src/models/system.js:481

  fetchLogo: async function () {
    const url = new URL(`${fullApiUrl()}/system/logo`);
    url.searchParams.append(
      "theme",
      localStorage.getItem("theme") || "default"
    );

    return await fetch(url, {
      method: "GET",
      cache: "no-cache",
    })
      .then(async (res) => {
        if (res.ok && res.status !== 204) {
          const isCustomLogo = res.headers.get("X-Is-Custom-Logo") === "true";
          const blob = await res.blob();
          const logoURL = URL.createObjectURL(blob);
          return { isCustomLogo, logoURL };
        }
        throw new Error("Failed to fetch logo!");
      })
      .catch((e) => {
        console.log(e);
        return { isCustomLogo: false, logoURL: null };
      });
  },
  fetchPfp: async function (id) {
    return await fetch(`${API_BASE}/system/pfp/${id}`, {
      method: "GET",
      cache: "no-cache",
      headers: baseHeaders(),
    })
      .then((res) => {
        if (res.ok && res.status !== 204) return res.blob();
        throw new Error("Failed to fetch pfp.");
      })
      .then((blob) => (blob ? URL.createObjectURL(blob) : null))
      .catch(() => {

View on GitHub (pinned to 526360e320)

Solutions

  1. Treat 204 as 'no custom logo' rather than an error — the guard conflates the two.
  2. Confirm fullApiUrl() returns the same origin that serves the /api routes.
  3. Check the server's logo storage path for a custom file.
  4. Ensure the reverse proxy preserves the ?theme= query string.

Example fix

// before
if (res.ok && res.status !== 204) { ... }
throw new Error("Failed to fetch logo!");

// after (204 is not an error)
if (res.status === 204) return { isCustomLogo: false, logoURL: null };
if (!res.ok) throw new Error(`Failed to fetch logo! (${res.status})`);
Defensive patterns

Strategy: fallback

Validate before calling

// No auth header is sent; ensure fullApiUrl() origin serves /system/logo.
function sameOriginLogoUrl() {
  try { return new URL(fullApiUrl()).origin === window.location.origin; }
  catch { return false; }
}

Type guard

/** @param {any} r @returns {r is {isCustomLogo:boolean, logoURL:string|null}} */
function isLogoResult(r) {
  return r != null && typeof r.isCustomLogo === "boolean" && (r.logoURL === null || typeof r.logoURL === "string");
}

Try / catch

const res = await System.fetchLogo();
if (!isLogoResult(res) || !res.logoURL) { renderDefaultLogo(); }

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of Mintplex-Labs/anything-llm@526360e320 (2026-08-13). Data as JSON: /api/errors/b89ed45d3967d91b. Report an issue: GitHub.