{"record":{"id":"f95aca8b126eff89","repo":"ipfs/kubo","slug":"err-error","errorCode":null,"errorMessage":"err.Error()","messagePattern":"err\\.Error\\(\\)","errorType":"http","errorClass":null,"httpStatus":500,"severity":"error","filePath":"core/corehttp/logs.go","lineNumber":63,"sourceCode":"\t\t\t\t\t\treturn\n\t\t\t\t\t}\n\t\t\t\t\t_, err = w.Write([]byte(line))\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\t// Failed to write to client, probably disconnected.\n\t\t\t\t\t\treturn\n\t\t\t\t\t}\n\t\t\t\t\tif f, ok := w.(http.Flusher); ok {\n\t\t\t\t\t\tf.Flush()\n\t\t\t\t\t}\n\t\t\t\t\tif r.Context().Err() != nil {\n\t\t\t\t\t\treturn\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}()\n\t\t\tlog.Info(\"log API client connected\")\n\t\t\terr := <-errs\n\t\t\tif err != nil {\n\t\t\t\thttp.Error(w, err.Error(), http.StatusInternalServerError)\n\t\t\t\treturn\n\t\t\t}\n\t\t})\n\t\treturn mux, nil\n\t}\n}\n","sourceCodeStart":45,"sourceCodeEnd":70,"githubUrl":"https://github.com/ipfs/kubo/blob/329838acdfafae224582930457efe80aa217afc0/core/corehttp/logs.go#L45-L70","documentation":"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.","triggerScenarios":"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).","commonSituations":"`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.","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)."],"exampleFix":"// before: naive client treats 500 as fatal\nresp, _ := http.Post(api+\"/api/v0/log/tail\", \"\", nil)\n// 500 -> abort\n\n// after: retry transient 500 with backoff\nfor i := 0; i < 3; i++ {\n  resp, err := http.Post(api+\"/api/v0/log/tail\", \"\", nil)\n  if err == nil && resp.StatusCode == 200 { break }\n  time.Sleep(time.Duration(1<<i) * time.Second)\n}","handlingStrategy":"retry","validationCode":"resp, err := http.Post(apiURL+\"/api/v0/log/tail\", \"\", nil)\nif err != nil { return err }\nif resp.StatusCode == http.StatusInternalServerError {\n    body, _ := io.ReadAll(io.LimitReader(resp.Body, 1<<12))\n    return fmt.Errorf(\"log endpoint unavailable (transient during shutdown): %s\", body)\n}","typeGuard":null,"tryCatchPattern":"for attempt := 0; attempt < 3; attempt++ {\n    resp, err := http.Post(api+\"/api/v0/log/tail\", \"\", nil)\n    if err == nil && resp.StatusCode == 200 {\n        return streamLogs(resp.Body)\n    }\n    time.Sleep(time.Duration(1<<attempt) * time.Second)\n}\nreturn errors.New(\"log endpoint kept returning 500; check daemon state\")","preventionTips":["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."],"tags":["logging","http","http-500","rpc-api"],"backgroundTag":"internal-server-error","analyzedSha":"329838acdfafae224582930457efe80aa217afc0","analyzedAt":"2026-09-03T18:30:52.135Z","contentChangedAt":"2026-09-03T18:30:52.135Z","schemaVersion":2},"datasetVersion":"2026-09-11T00:17:11.886Z"}