gRPC: INVALID_ARGUMENT (code 3)
The server understood the request and rejected the field values. Because protobuf 3 has no required fields and unset scalars deserialise to zero values, a client that forgot to set a field sends a syntactically valid message that fails validation on arrival.
Quick fix
Read the commands before running them. Anything that restarts a service, deletes data or changes permissions should be tried on a non-production system first.
# Print what you are actually sending
grpcurl -d '{"page_size":0}' -vv host:443 pkg.Service/Method
# Distinguish unset from zero with a wrapper or optional
message Query {
optional int32 page_size = 1; // proto3 optional gives you has_page_size()
}
# Validate in one place with protovalidate
import "buf/validate/validate.proto";
int32 page_size = 1 [(buf.validate.field).int32 = {gte: 1, lte: 100}];
How to diagnose gRPC errors
Every gRPC call ends with a status code, and the code tells you which layer failed. UNAVAILABLE and INTERNAL are transport: the connection, the proxy or the HTTP/2 stream, not your handler. UNAUTHENTICATED, PERMISSION_DENIED and UNIMPLEMENTED mean the request arrived and was rejected before your logic ran. INVALID_ARGUMENT, FAILED_PRECONDITION and ABORTED are your service answering deliberately. The distinction matters most for retries: UNAVAILABLE and ABORTED are safe to retry, FAILED_PRECONDITION and INVALID_ARGUMENT never are, and retrying them turns one bad request into a storm.
If the quick fix above does not resolve it, work through these steps. They apply to this whole class of error, not just to this one message, which is usually what saves the time.
- Read the code and the message together.
grpcurl -vvprints the status, the message and anygoogle.rpcerror details the server attached, which is far more than most client libraries surface by default. - Establish whether the call reached your handler at all. Log at the first line of the method: if nothing appears, the failure is in the transport, the proxy or an interceptor, and reading your business logic is wasted effort.
- Enable the runtime's own transport logging.
GRPC_GO_LOG_SEVERITY_LEVEL=info GRPC_GO_LOG_VERBOSITY_LEVEL=2for Go, orGRPC_VERBOSITY=debug GRPC_TRACE=http,call_errorfor the C based implementations, exposes HTTP/2 resets and name resolution that the status code hides. - Check that HTTP/2 survives the whole path. Any load balancer that terminates at layer 7 without HTTP/2 support, or an idle timeout shorter than your keepalive, produces stream resets that surface as INTERNAL or UNAVAILABLE on a service that is perfectly healthy.
- Confirm both sides were generated from the same .proto. A method rename, a package change or a stale generated file gives UNIMPLEMENTED, and
grpcurl listagainst a server with reflection enabled settles it in one command. - For anything size or time related, remember the limits are enforced per side: the 4 MB receive limit, the client deadline and the server's max connection age each belong to one peer, so raising one alone often just moves the failure.
Tools worth reaching for
grpcurlgrpc_health_probeGRPC_GO_LOG_SEVERITY_LEVEL / GRPC_TRACEbuf lint && buf breakingWireshark or tcpdump with HTTP/2 decodingEnvoy access logs
Authoritative references
Primary documentation for this error, worth reading before applying any fix in production.
Related gRPC errors
- gRPC-Web: response missing grpc-status trailerBrowsers cannot speak native gRPC, so gRPC-Web encodes trailers in the response body and…
- gRPC: ABORTED (code 10)The operation was aborted because of a concurrency conflict, typically a failed compare and…
- gRPC: DEADLINE_EXCEEDED (code 4)The client set a deadline on the call and the server did not finish in time. gRPC deadlines…
- gRPC: FAILED_PRECONDITION (code 9)The request was valid but the system is in a state that cannot serve it, for example a…
- gRPC: INTERNAL, received RST_STREAM with error code 2The HTTP/2 stream was reset by the peer or by something in the middle. It is rarely a bug in…
- gRPC: PERMISSION_DENIED (code 7)The caller was identified but is not allowed to invoke this method. Unlike UNAUTHENTICATED…
- gRPC: RESOURCE_EXHAUSTED, received message larger than maxA message exceeded the receiver's size limit, which defaults to 4 MB inbound in most gRPC…
- gRPC: UNAUTHENTICATED (code 16)The server rejected the call because credentials were missing, malformed or expired. gRPC…
Browse other categories
- HTTP 494xx client errors, 5xx server errors, redirects, headers and protocol problems.
- JavaScript 42npm resolution, async pitfalls, hydration, memory limits and runtime type…
- Database 41Connections, deadlocks, constraints, replication and memory limits.
- AI 35Rate limits, context windows, GPU memory and model-serving failures.
- Network 35Refused connections, timeouts, resets, MTU problems and port exhaustion.
- Python 35Imports, virtual environments, encoding, concurrency and dependency conflicts.
- Kubernetes 34CrashLoopBackOff, ImagePullBackOff, OOMKilled, RBAC, scheduling and storage.
- Docker 27Daemon connectivity, disk space, image pulls, ports and architecture mismatches.
- System 26Disk space, systemd units, file descriptors, OOM killer and scheduled jobs.
- Cloud 25IAM permissions, quotas, service limits and credential failures.
- Security 25JWT validation, CSRF, OAuth grants, SELinux, SSH host keys and CSP.
- TLS 24Untrusted authorities, expiry, hostname mismatch, chains and cipher negotiation.
Something missing or wrong?
This entry is maintained by hand. If the fix is out of date, incomplete, or you have a better one, email a correction and it will be reviewed.