{"record":{"id":"88778159aabf2f9e","repo":"projectdiscovery/nuclei","slug":"grpc-status-s-s","errorCode":null,"errorMessage":"grpc status %s: %s","messagePattern":"grpc status (.+?): (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/js/libs/grpc/invoke.go","lineNumber":151,"sourceCode":"\tparser, formatter, err := grpcurl.RequestParserAndFormatter(grpcurl.FormatJSON, src, in, grpcurl.FormatOptions{\n\t\tEmitJSONDefaultFields: true,\n\t\tAllowUnknownFields:    false,\n\t})\n\tif err != nil {\n\t\treturn \"\", fmt.Errorf(\"failed to build request parser: %w\", err)\n\t}\n\n\tvar out bytes.Buffer\n\thandler := &grpcurl.DefaultEventHandler{\n\t\tOut:       &out,\n\t\tFormatter: formatter,\n\t}\n\n\tif err := grpcurl.InvokeRPC(ctx, src, cc, method, headers, handler, parser.Next); err != nil {\n\t\treturn \"\", err\n\t}\n\tif handler.Status != nil && handler.Status.Code() != codes.OK {\n\t\treturn \"\", fmt.Errorf(\"grpc status %s: %s\", handler.Status.Code().String(), handler.Status.Message())\n\t}\n\treturn strings.TrimRight(out.String(), \"\\n\"), nil\n}\n\n// describeSymbol returns the textual descriptor for a fully-qualified symbol.\nfunc describeSymbol(src grpcurl.DescriptorSource, symbol string) (string, error) {\n\tdsc, err := src.FindSymbol(symbol)\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\treturn grpcurl.GetDescriptorText(dsc, src)\n}\n","sourceCodeStart":133,"sourceCodeEnd":164,"githubUrl":"https://github.com/projectdiscovery/nuclei/blob/265b3a3dec374741614e342f813c10f8b38d2bb7/pkg/js/libs/grpc/invoke.go#L133-L164","documentation":"The RPC completed at the transport level but the server returned a non-OK gRPC status, surfaced as 'grpc status <CODE>: <MESSAGE>'. Dialing, TLS, and network-policy checks already passed; this is the server's application-level answer (Unimplemented, Unavailable, DeadlineExceeded, PermissionDenied, InvalidArgument, etc.).","triggerScenarios":"Wrong method name -> Unimplemented; Plaintext mismatch (TLS client against an h2c server, or vice versa) -> Unavailable; opts.TimeoutSeconds too small -> DeadlineExceeded; missing auth metadata -> PermissionDenied; schema-invalid argument values -> InvalidArgument.","commonSituations":"Probing a non-gRPC port (plain HTTP server) -> Unavailable/Unimplemented, which is itself a useful fingerprint; version drift between template method names and the deployed service; endpoints requiring metadata the template never sends.","solutions":["Match transport to endpoint: opts.Plaintext = true for h2c servers, default TLS otherwise","Send required metadata: client.InvokeWithHeaders('acme.v1.Svc/Get', '{}', ['authorization: Bearer ' + token])","Raise opts.TimeoutSeconds for slow methods and verify the method name with ListMethods()","Branch on the status code string: Unimplemented/Unavailable on a port is a detection signal, not just a failure"],"exampleFix":"// before: TLS client against an h2c endpoint, no metadata\nconst client = new grpc.Client('grpc.acme.com:50051');\nconst resp = client.Invoke('acme.v1.Svc/Get', '{}'); // -> grpc status Unavailable\n\n// after: correct transport + metadata\nconst o = new grpc.Options();\no.Plaintext = true;\nconst c = new grpc.Client('grpc.acme.com:50051', o);\nconst resp = c.InvokeWithHeaders('acme.v1.Svc/Get', '{}', ['authorization: Bearer ' + tok]);","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try {\n  const resp = client.InvokeWithHeaders(method, '{}', headers);\n} catch (e) {\n  const m = /^grpc status (\\w+):/.exec(e.message || '');\n  if (m) {\n    switch (m[1]) {\n      case 'Unavailable':     /* check Plaintext/TLS option and port */ break;\n      case 'Unimplemented':   /* wrong method name or non-gRPC port */ break;\n      case 'DeadlineExceeded':/* raise opts.TimeoutSeconds */ break;\n      case 'PermissionDenied':/* send auth metadata via InvokeWithHeaders */ break;\n      default:                /* surface the server message as the finding context */\n    }\n  }\n}","preventionTips":["Confirm Plaintext/TLS mode matches the endpoint before invoking","Verify method names with ListMethods instead of guessing","Send required metadata with InvokeWithHeaders from the start","Parse the status code out of the message and branch — some codes are detections, not failures"],"tags":["grpc","javascript","server-error"],"backgroundTag":null,"analyzedSha":"265b3a3dec374741614e342f813c10f8b38d2bb7","analyzedAt":"2026-08-15T20:05:51.855Z","schemaVersion":2},"datasetVersion":"2026-08-16T03:17:38.424Z"}