{"record":{"id":"eccbf06e8a08ab0c","repo":"apache/beam","slug":"failed-to-read-metadata-from-context","errorCode":null,"errorMessage":"failed to read metadata from context","messagePattern":"failed to read metadata from context","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"sdks/go/pkg/beam/util/grpcx/metadata.go","lineNumber":32,"sourceCode":"// limitations under the License.\n\n// Package grpcx contains utilities for working with gRPC.\npackage grpcx\n\nimport (\n\t\"context\"\n\n\t\"github.com/apache/beam/sdks/v2/go/pkg/beam/internal/errors\"\n\t\"google.golang.org/grpc/metadata\"\n)\n\nconst idKey = \"worker_id\"\n\n// ReadWorkerID reads the worker ID from an incoming gRPC request context.\nfunc ReadWorkerID(ctx context.Context) (string, error) {\n\tmd, ok := metadata.FromIncomingContext(ctx)\n\tif !ok {\n\t\treturn \"\", errors.New(\"failed to read metadata from context\")\n\t}\n\tid, ok := md[idKey]\n\tif !ok || len(id) < 1 {\n\t\treturn \"\", errors.Errorf(\"failed to find worker id in metadata %v\", md)\n\t}\n\tif len(id) > 1 {\n\t\treturn \"\", errors.Errorf(\"multiple worker ids in metadata: %v\", id)\n\t}\n\treturn id[0], nil\n}\n\n// WriteWorkerID write the worker ID to an outgoing gRPC request context. It\n// merges the information with any existing gRPC metadata.\nfunc WriteWorkerID(ctx context.Context, id string) context.Context {\n\tmd := metadata.New(map[string]string{\n\t\tidKey: id,\n\t})\n\tif old, ok := metadata.FromOutgoingContext(ctx); ok {","sourceCodeStart":14,"sourceCodeEnd":50,"githubUrl":"https://github.com/apache/beam/blob/12126d8942aaf848030c478b4c6a28c6af861c66/sdks/go/pkg/beam/util/grpcx/metadata.go#L14-L50","documentation":"grpcx.ReadWorkerID extracts the 'worker_id' key from a gRPC incoming metadata context; the FnAPI/JobAPI servers use it to identify which worker sent a request. This error means the incoming gRPC context carries no metadata at all, so the worker ID cannot be read. Callers typically abort or ignore the request since attribution is impossible.","triggerScenarios":"Calling grpcx.ReadWorkerID(ctx) on a context where metadata.FromIncomingContext(ctx) returns ok==false — i.e. the request arrived without gRPC metadata (e.g. a client built without grpcx.WriteWorkerID, a raw test connection, a health check, or a non-Beam client hitting the worker endpoint).","commonSituations":"Unit tests calling the Beam worker/harness service handlers with plain context.Background(); load balancers or probes dialing the gRPC port; custom clients or older SDK workers not stamping worker_id metadata; multiplexed servers where non-Beam RPCs land on the same listener.","solutions":["Ensure every worker-side client writes the ID before dialing: wrap the context with grpcx.WriteWorkerID(ctx, workerID) and pass it to grpc.DialContext.","In tests, construct the incoming context with metadata.NewIncomingContext(ctx, metadata.Pairs(\"worker_id\", \"test-worker\")).","Treat the returned error as 'unknown caller' and reject or log-and-continue depending on the endpoint (e.g. skip attribution for probes).","Check for middleware that strips incoming metadata, and for version skew where an old worker binary predates worker_id stamping."],"exampleFix":"// before\nconn, _ := grpc.DialContext(ctx, addr, ...) // no worker id metadata\n\n// after\nctx = grpcx.WriteWorkerID(ctx, \"worker-1\")\nconn, _ := grpc.DialContext(ctx, addr, grpc.WithContextDialer(dialerWith(ctx)), ...)","handlingStrategy":"try-catch","validationCode":"if _, ok := metadata.FromIncomingContext(ctx); !ok {\n    // no metadata: handle unknown-caller path before calling ReadWorkerID\n}","typeGuard":"func hasIncomingMetadata(ctx context.Context) bool {\n    _, ok := metadata.FromIncomingContext(ctx)\n    return ok\n}","tryCatchPattern":"id, err := grpcx.ReadWorkerID(ctx)\nif err != nil {\n    log.Printf(\"request without worker_id metadata: %v\", err)\n    return status.Error(codes.InvalidArgument, \"missing worker id metadata\")\n}","preventionTips":["Always create worker gRPC connections via grpcx.WriteWorkerID so metadata is stamped consistently.","In tests, build incoming contexts with metadata.NewIncomingContext and the worker_id key.","Exclude probes/health checks from endpoints that require worker attribution."],"tags":["grpc","go","metadata","apache-beam"],"backgroundTag":"missing-credentials","analyzedSha":"12126d8942aaf848030c478b4c6a28c6af861c66","analyzedAt":"2026-09-13T01:50:10.254Z","contentChangedAt":"2026-09-13T01:50:10.254Z","schemaVersion":2},"datasetVersion":"2026-09-14T16:17:12.679Z"}