ipfs/kubo · error
err.Error()
Error message
err.Error()
What it means
The log endpoint handler waits on an internal error channel; if the streaming goroutine reports an error (see 'error reading log message'), the handler responds with HTTP 500 whose body is err.Error(). This surfaces the underlying log-pipe failure to the HTTP client as a 500 response.
Source
Thrown at core/corehttp/logs.go:63
return
}
_, err = w.Write([]byte(line))
if err != nil {
// Failed to write to client, probably disconnected.
return
}
if f, ok := w.(http.Flusher); ok {
f.Flush()
}
if r.Context().Err() != nil {
return
}
}
}()
log.Info("log API client connected")
err := <-errs
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
})
return mux, nil
}
}
View on GitHub (pinned to 329838acdf)
Solutions
- Retry the log-stream request once the daemon is confirmed running (`ipfs id`); a 500 here is usually transient shutdown-state.
- Do not scrape the log endpoint during daemon restarts; wait for readiness before tailing.
- Read the on-disk daemon log file as a fallback when the streaming endpoint returns 500.
- If it persists on a healthy daemon, check the API port is not pointed at a stale/proxied daemon and file an issue with the body text (it contains the underlying error).
Example fix
// before: naive client treats 500 as fatal
resp, _ := http.Post(api+"/api/v0/log/tail", "", nil)
// 500 -> abort
// after: retry transient 500 with backoff
for i := 0; i < 3; i++ {
resp, err := http.Post(api+"/api/v0/log/tail", "", nil)
if err == nil && resp.StatusCode == 200 { break }
time.Sleep(time.Duration(1<<i) * time.Second)
} Defensive patterns
Strategy: retry
Validate before calling
resp, err := http.Post(apiURL+"/api/v0/log/tail", "", nil)
if err != nil { return err }
if resp.StatusCode == http.StatusInternalServerError {
body, _ := io.ReadAll(io.LimitReader(resp.Body, 1<<12))
return fmt.Errorf("log endpoint unavailable (transient during shutdown): %s", body)
} Try / catch
for attempt := 0; attempt < 3; attempt++ {
resp, err := http.Post(api+"/api/v0/log/tail", "", nil)
if err == nil && resp.StatusCode == 200 {
return streamLogs(resp.Body)
}
time.Sleep(time.Duration(1<<attempt) * time.Second)
}
return errors.New("log endpoint kept returning 500; check daemon state") Prevention
- Retry 500s from the log endpoint with backoff; they are typically shutdown-transient.
- Verify daemon health (`ipfs id`) before blaming the endpoint.
- Use the on-disk log file as a fallback when the streaming endpoint fails.
- The 500 body contains the underlying cause — read it before retrying blindly.
When it happens
Trigger: Connecting to the log-streaming HTTP endpoint and receiving a 500 — happens when the read goroutine fails before/while streaming (pipe closed, daemon shutting down, I/O error on the log pipe).
Common situations: `ipfs log tail` clients that hit the RPC API of a daemon that is shutting down; requests arriving right after the log writer closed; monitoring scripts scraping the log endpoint during restarts.
Related errors
- error reading log message: %s
- unexpected redirect
- serveHTTPApi: %w
- GitHub API returned HTTP %d for %s
- download returned HTTP %d
AI-assisted analysis of ipfs/kubo@329838acdf (2026-09-03).
Data as JSON: /api/errors/f95aca8b126eff89.
Report an issue: GitHub.