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

  1. Retry the log-stream request once the daemon is confirmed running (`ipfs id`); a 500 here is usually transient shutdown-state.
  2. Do not scrape the log endpoint during daemon restarts; wait for readiness before tailing.
  3. Read the on-disk daemon log file as a fallback when the streaming endpoint returns 500.
  4. 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

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


AI-assisted analysis of ipfs/kubo@329838acdf (2026-09-03). Data as JSON: /api/errors/f95aca8b126eff89. Report an issue: GitHub.