projectdiscovery/nuclei · error
grpc status %s: %s
Error message
grpc status %s: %s
What it means
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.).
Source
Thrown at pkg/js/libs/grpc/invoke.go:151
parser, formatter, err := grpcurl.RequestParserAndFormatter(grpcurl.FormatJSON, src, in, grpcurl.FormatOptions{
EmitJSONDefaultFields: true,
AllowUnknownFields: false,
})
if err != nil {
return "", fmt.Errorf("failed to build request parser: %w", err)
}
var out bytes.Buffer
handler := &grpcurl.DefaultEventHandler{
Out: &out,
Formatter: formatter,
}
if err := grpcurl.InvokeRPC(ctx, src, cc, method, headers, handler, parser.Next); err != nil {
return "", err
}
if handler.Status != nil && handler.Status.Code() != codes.OK {
return "", fmt.Errorf("grpc status %s: %s", handler.Status.Code().String(), handler.Status.Message())
}
return strings.TrimRight(out.String(), "\n"), nil
}
// describeSymbol returns the textual descriptor for a fully-qualified symbol.
func describeSymbol(src grpcurl.DescriptorSource, symbol string) (string, error) {
dsc, err := src.FindSymbol(symbol)
if err != nil {
return "", err
}
return grpcurl.GetDescriptorText(dsc, src)
}
View on GitHub (pinned to 265b3a3dec)
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
Example fix
// before: TLS client against an h2c endpoint, no metadata
const client = new grpc.Client('grpc.acme.com:50051');
const resp = client.Invoke('acme.v1.Svc/Get', '{}'); // -> grpc status Unavailable
// after: correct transport + metadata
const o = new grpc.Options();
o.Plaintext = true;
const c = new grpc.Client('grpc.acme.com:50051', o);
const resp = c.InvokeWithHeaders('acme.v1.Svc/Get', '{}', ['authorization: Bearer ' + tok]); Defensive patterns
Strategy: try-catch
Try / catch
try {
const resp = client.InvokeWithHeaders(method, '{}', headers);
} catch (e) {
const m = /^grpc status (\w+):/.exec(e.message || '');
if (m) {
switch (m[1]) {
case 'Unavailable': /* check Plaintext/TLS option and port */ break;
case 'Unimplemented': /* wrong method name or non-gRPC port */ break;
case 'DeadlineExceeded':/* raise opts.TimeoutSeconds */ break;
case 'PermissionDenied':/* send auth metadata via InvokeWithHeaders */ break;
default: /* surface the server message as the finding context */
}
}
} Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- invalid grpc target %q (expected host:port): %w
- grpc target host cannot be empty
- grpc: refusing to dial without executionId
- grpc: dialers not initialized for executionId %q
- failed to build request parser: %w
AI-assisted analysis of projectdiscovery/nuclei@265b3a3dec (2026-08-15).
Data as JSON: /api/errors/88778159aabf2f9e.
Report an issue: GitHub.