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

  1. Match transport to endpoint: opts.Plaintext = true for h2c servers, default TLS otherwise
  2. Send required metadata: client.InvokeWithHeaders('acme.v1.Svc/Get', '{}', ['authorization: Bearer ' + token])
  3. Raise opts.TimeoutSeconds for slow methods and verify the method name with ListMethods()
  4. 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

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


AI-assisted analysis of projectdiscovery/nuclei@265b3a3dec (2026-08-15). Data as JSON: /api/errors/88778159aabf2f9e. Report an issue: GitHub.