{"record":{"id":"9e1454d67506c478","repo":"micro/go-micro","slug":"connection-header-set-to-close","errorCode":null,"errorMessage":"connection header set to close","messagePattern":"connection header set to close","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"info","filePath":"client/rpc_stream.go","lineNumber":180,"sourceCode":"\t\t// send the end of stream message\n\t\tif r.sendEOS {\n\t\t\t// no need to check for error\n\t\t\t//nolint:errcheck,gosec\n\t\t\tr.codec.Write(&codec.Message{\n\t\t\t\tId:       r.id,\n\t\t\t\tTarget:   r.request.Service(),\n\t\t\t\tMethod:   r.request.Method(),\n\t\t\t\tEndpoint: r.request.Endpoint(),\n\t\t\t\tType:     codec.Error,\n\t\t\t\tError:    lastStreamResponseError,\n\t\t\t}, nil)\n\t\t}\n\n\t\terr := r.codec.Close()\n\n\t\trerr := r.Error()\n\t\tif r.close && rerr == nil {\n\t\t\trerr = errors.New(\"connection header set to close\")\n\t\t}\n\t\t// release the connection\n\t\tr.release(rerr)\n\n\t\treturn err\n\t}\n}\n","sourceCodeStart":162,"sourceCodeEnd":188,"githubUrl":"https://github.com/micro/go-micro/blob/24529f140421a11a33b6999ab7944f2021cfd69c/client/rpc_stream.go#L162-L188","documentation":"In client/rpc_stream.go:180, rpcStream.Close closes the codec and then checks r.Error(); if the stream was marked with r.close and no other error occurred, it synthesizes errors.New(\"connection header set to close\") as the stream error before releasing the connection. This signals that the connection was intentionally torn down because the close flag was set (the underlying transport/connection header requested closure).","triggerScenarios":"Closing a stream when r.close is true — i.e. the transport indicated the connection should be closed (connection: close semantics) — while the codec itself closed without error.","commonSituations":"HTTP/1.1 connections with connection: close being recycled; server asking clients not to reuse connections; pool eviction on stream teardown.","solutions":["Ignore this error when it indicates an expected connection teardown (compare against the message or just log at debug level)","Check r.Error() before Close to distinguish real stream errors from the teardown sentinel","Ensure connection pooling re-establishes connections rather than treating this as fatal"],"exampleFix":"// before\nif err := stream.Close(); err != nil { return err }\n// after\nif err := stream.Close(); err != nil && !strings.Contains(err.Error(), \"connection header set to close\") {\n    return err\n}","handlingStrategy":"type-guard","validationCode":"// optional: inspect stream error before closing to separate real faults\nserr := stream.Error() // if non-nil, real failure; Close()'s sentinel is noise","typeGuard":"func isConnCloseTeardown(err error) bool {\n    return err != nil && strings.Contains(err.Error(), \"connection header set to close\")\n}","tryCatchPattern":"if err := stream.Close(); err != nil && !isConnCloseTeardown(err) {\n    return fmt.Errorf(\"stream close failed: %w\", err)\n}\n// teardown sentinel ignored","preventionTips":["Treat this error as informational connection teardown, not a fault","Ensure your connection pool handles non-reusable connections","Log real stream errors (stream.Error()) separately from close-time sentinels"],"tags":["stream","connection","close","rpc","micro"],"backgroundTag":"connection-closed","analyzedSha":"24529f140421a11a33b6999ab7944f2021cfd69c","analyzedAt":"2026-09-01T02:52:24.923Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T05:18:18.240Z"}