{"record":{"id":"d331b12d713bed50","repo":"glanceapp/glance","slug":"decoding-response-w","errorCode":null,"errorMessage":"decoding response: %w","messagePattern":"decoding response: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/glance/widget-docker-containers.go","lineNumber":337,"sourceCode":"\n\trequest, err := http.NewRequestWithContext(ctx, \"GET\", \"http://\"+hostname+\"/containers/json?all=\"+fetchAll, nil)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"creating request: %w\", err)\n\t}\n\n\tresponse, err := client.Do(request)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"sending request to socket: %w\", err)\n\t}\n\tdefer response.Body.Close()\n\n\tif response.StatusCode != http.StatusOK {\n\t\treturn nil, fmt.Errorf(\"non-200 response status: %s\", response.Status)\n\t}\n\n\tvar containers []dockerContainerJsonResponse\n\tif err := json.NewDecoder(response.Body).Decode(&containers); err != nil {\n\t\treturn nil, fmt.Errorf(\"decoding response: %w\", err)\n\t}\n\n\tfor i := range containers {\n\t\tcontainer := &containers[i]\n\t\tname := strings.TrimLeft(itemAtIndexOrDefault(container.Names, 0, \"\"), \"/\")\n\n\t\tif name == \"\" {\n\t\t\tcontinue\n\t\t}\n\n\t\toverrides, ok := labelOverrides[name]\n\t\tif !ok {\n\t\t\tcontinue\n\t\t}\n\n\t\tif container.Labels == nil {\n\t\t\tcontainer.Labels = make(dockerContainerLabels)\n\t\t}","sourceCodeStart":319,"sourceCodeEnd":355,"githubUrl":"https://github.com/glanceapp/glance/blob/91324e8de762702e97b0ac5c8e36271d644d8642/internal/glance/widget-docker-containers.go#L319-L355","documentation":"The response body from /containers/json could not be JSON-decoded into the container list. Docker's API always returns valid JSON, so this means the body was truncated, an HTML error page was returned by an intermediary, or the endpoint is not the Docker API at all.","triggerScenarios":"A proxy returns an HTML error page with a 200 status; connection dropped mid-body (unexpected EOF); non-Docker service on the target port returning 200 with non-JSON content.","commonSituations":"tcp:// source pointing at a web server; flaky network truncating responses; intermediate caching proxy mangling the response.","solutions":["Fetch the raw body manually with curl and inspect whether it is JSON: curl --unix-socket ... | head -c 200","Point the source directly at the Docker API endpoint without proxies","If truncation is suspected, fix the unstable network link to the remote Docker host"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"body, err := io.ReadAll(io.LimitReader(response.Body, 1<<20))\nif err == nil && len(body) > 0 && body[0] != '{' && body[0] != '[' {\n    return fmt.Errorf(\"non-JSON response from %s (first byte %q)\", hostname, body[0])\n}","typeGuard":null,"tryCatchPattern":"var containers []dockerContainerJsonResponse\nif err := json.NewDecoder(response.Body).Decode(&containers); err != nil {\n    slog.Warn(\"docker response not JSON — is a proxy in front of the API?\", \"host\", hostname, \"error\", err)\n    return nil, err\n}","preventionTips":["Never put a caching/HTML proxy between the widget and the Docker API","Alert on content-type: application/json absence in responses from the configured source"],"tags":["docker","json","decode","proxy"],"backgroundTag":null,"analyzedSha":"91324e8de762702e97b0ac5c8e36271d644d8642","analyzedAt":"2026-08-15T14:12:54.279Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}