amir20/dozzle · error · Error

Failed to fetch logs

Error message

Failed to fetch logs: ${response.statusText}

What it means

LogAnalytics.vue fetches the full log payload (for DuckDB analytics) and throws `Failed to fetch logs: ${response.statusText}` when response.ok is false. This is a manual guard: the fetch API itself does not throw on HTTP error statuses, so the component converts bad statuses into an exception that its catch block turns into an error UI state.

Solutions

  1. Inspect the failing request's status code and body in DevTools Network tab
  2. Re-authenticate if the status is 401/403, then reload the analytics view
  3. Retry when the host/container is back online; verify the container id in the URL is current
  4. Include response.status in the message since statusText can be empty on HTTP/2

Example fix

// before
throw new Error(`Failed to fetch logs: ${response.statusText}`);
// after
throw new Error(`Failed to fetch logs: ${response.status} ${response.statusText || "unknown error"}`);
Defensive patterns

Strategy: try-catch

Validate before calling

const head = await fetch(url, { method: "HEAD" });
if (!head.ok) throw new Error(`Logs endpoint unavailable: ${head.status}`);

Try / catch

try {
  await loadAnalytics();
} catch (e) {
  state.value = "error";
  errorMessage.value = e instanceof Error ? e.message : "unknown";
}

Prevention

When it happens

Trigger: Opening the log analytics view while the fetch(url) call (logs export endpoint for the container/host) returns non-2xx: container id no longer exists, host disconnected, 401 from expired session, or proxy 5xx during large log download.

Common situations: Large containers where the backend times out and a proxy returns 504; container recreated with a new id so the old URL 404s; auth middleware rejecting a stale JWT; running behind a load balancer with a short request timeout.

Understand the failure class

Background: 'Something went wrong' / 'Request failed (500)' / 'HTTP error! status: 404' — what failed HTTP requests actually mean and how to find the real cause — this error's family across 28 libraries.

Related errors


AI-assisted analysis of amir20/dozzle@d9463cbe21 (2026-09-07). Data as JSON: /api/errors/0eaaf134266950d1. Report an issue: GitHub.

Appendix: source

Thrown at assets/components/LogViewer/LogAnalytics.vue:137

const evaluating = ref(false);
const pageLimit = 1000;
const state = ref<"downloading" | "ready" | "initializing">("downloading");
const bytes = ref(0);
const columns = ref<{ name: string; type: string }[]>([]);
const queryEl = useTemplateRef<HTMLTextAreaElement>("queryEl");

const runQuery = ref(query.value);
watchDebounced(query, (v) => (runQuery.value = v), { debounce: 500 });

const url = withBase(
  `/api/hosts/${container.host}/containers/${container.id}/logs?stdout=1&stderr=1&everything&jsonOnly`,
);

const [{ useDuckDB }, response] = await Promise.all([import(`@/composable/duckdb`), fetch(url)]);

if (!response.ok) {
  console.log("error fetching logs from", url);
  throw new Error(`Failed to fetch logs: ${response.statusText}`);
}

const { db, conn } = await useDuckDB();
const empty = await conn.query<Record<string, any>>(`SELECT 1 LIMIT 0`);

onMounted(async () => {
  try {
    state.value = "downloading";

    const reader = response.body?.getReader();
    if (!reader) throw new Error("No reader available from stream");

    const chunks: Uint8Array[] = [];
    bytes.value = 0;

    while (true) {
      const { done, value } = await reader.read();
      if (done) break;

View on GitHub (pinned to d9463cbe21)