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
- Inspect the failing request's status code and body in DevTools Network tab
- Re-authenticate if the status is 401/403, then reload the analytics view
- Retry when the host/container is back online; verify the container id in the URL is current
- 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
- Verify the container id/host in the URL is current before opening analytics
- Raise proxy timeouts for large log exports
- Log response.status, not just statusText, for diagnosis
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
- response.statusText
- No reader available from stream
- (await res.json().catch(() =>
- (await res.json().catch(() =>
- Failed to save alert
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)