{"record":{"id":"8c371426941121ce","repo":"grpc/grpc-go","slug":"request-info-not-found-from-context","errorCode":null,"errorMessage":"request info not found from context","messagePattern":"request info not found from context","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"credentials/google/google.go","lineNumber":167,"sourceCode":"\tif mode == internal.CredsBundleModeFallback || mode == internal.CredsBundleModeBackendFromBalancer {\n\t\tnewCreds.perRPCCreds = newCreds.opts.PerRPCCreds\n\t}\n\n\treturn newCreds, nil\n}\n\n// dualPerRPCCreds implements credentials.PerRPCCredentials by embedding the\n// fallback PerRPCCredentials and the ALTS one. It pickes one of them based on\n// the channel type.\ntype dualPerRPCCreds struct {\n\tperRPCCreds     credentials.PerRPCCredentials\n\taltsPerRPCCreds credentials.PerRPCCredentials\n}\n\nfunc (d *dualPerRPCCreds) GetRequestMetadata(ctx context.Context, uri ...string) (map[string]string, error) {\n\tri, ok := credentials.RequestInfoFromContext(ctx)\n\tif !ok {\n\t\treturn nil, fmt.Errorf(\"request info not found from context\")\n\t}\n\tif authType := ri.AuthInfo.AuthType(); authType == \"alts\" {\n\t\treturn d.altsPerRPCCreds.GetRequestMetadata(ctx, uri...)\n\t}\n\t// This ensures backward compatibility even if authType is not \"tls\".\n\treturn d.perRPCCreds.GetRequestMetadata(ctx, uri...)\n}\n\nfunc (d *dualPerRPCCreds) RequireTransportSecurity() bool {\n\treturn d.altsPerRPCCreds.RequireTransportSecurity() || d.perRPCCreds.RequireTransportSecurity()\n}\n","sourceCodeStart":149,"sourceCodeEnd":179,"githubUrl":"https://github.com/grpc/grpc-go/blob/03255a9237b6eb32710f6bc4f2de9a675b99fe36/credentials/google/google.go#L149-L179","documentation":"dualPerRPCCreds.GetRequestMetadata requires credentials.RequestInfoFromContext(ctx) to return ok=true so it can inspect AuthInfo.AuthType() and pick ALTS vs TLS per-RPC creds (google.go:165-168). gRPC's transport layer always attaches RequestInfo before invoking GetRequestMetadata, so ok=false means the call was made outside the normal RPC path.","triggerScenarios":"Calling dualPerRPCCreds.GetRequestMetadata directly from application or test code without using credentials.NewContextWithRequestInfo to attach RequestInfo, or a custom transport stack that did not set requestInfoKey on the context.","commonSituations":"Unit tests exercising per-RPC creds in isolation, a manually-constructed context for a custom transport, or a gRPC version mismatch where the key attachment contract changed.","solutions":["Do not call GetRequestMetadata manually; let gRPC invoke it during a real RPC where RequestInfo is attached.","In tests, build the context with credentials.NewContextWithRequestInfo(ctx, credentials.RequestInfo{AuthInfo: ...}) before calling.","If you maintain a custom transport, set requestInfoKey via NewContextWithRequestInfo before per-RPC credential calls."],"exampleFix":"// before (test): context has no RequestInfo\nmd, err := dualCreds.GetRequestMetadata(context.Background())\n\n// after (test): attach RequestInfo like gRPC does\nctx := credentials.NewContextWithRequestInfo(context.Background(), credentials.RequestInfo{\n    AuthInfo: /* your AuthInfo impl */,\n})\nmd, err := dualCreds.GetRequestMetadata(ctx)","handlingStrategy":"validation","validationCode":"// In tests, attach RequestInfo exactly like gRPC does.\nfunc ctxWithRequestInfo(ctx context.Context, ai credentials.AuthInfo) context.Context {\n    return credentials.NewContextWithRequestInfo(ctx, credentials.RequestInfo{AuthInfo: ai})\n}\nmd, err := dualCreds.GetRequestMetadata(ctxWithRequestInfo(ctx, ai))","typeGuard":null,"tryCatchPattern":"md, err := dualCreds.GetRequestMetadata(ctx)\nif err != nil && strings.Contains(err.Error(), \"request info not found from context\") {\n    // called outside the RPC path: attach RequestInfo or invoke via a real RPC.\n    return nil, fmt.Errorf(\"GetRequestMetadata called without RequestInfo in context: %w\", err)\n}","preventionTips":["Do not call GetRequestMetadata manually outside the gRPC transport path.","In tests, always wrap the context with credentials.NewContextWithRequestInfo.","If maintaining a custom transport, set requestInfoKey before per-RPC cred calls.","Treat this error as a test-harness bug, not a runtime failure."],"tags":["grpc","credentials","context","testing"],"analyzedSha":"03255a9237b6eb32710f6bc4f2de9a675b99fe36","analyzedAt":"2026-08-07T00:29:34.215Z","schemaVersion":2},"datasetVersion":"2026-08-07T03:17:09.362Z"}