#1543·grpc-web

When grpc-web (browser) receives a 400 or 500 level error, metadata is empty

Author: EraYaNCreated Aug 5, 2026Updated Aug 5, 2026

It seems like the error object in the following snippet does not contain any metadata it also does not use the actual message from grpc-message header. (error as any).metadata returns an empty map.

javascript
let client=new GrpcWebClientBase(this.settings);
let client.rpcCall(
        host + path,
        req,
        metadata?.toObject() ?? {},
        descriptor,
        (error, data) => {
          if (error) {
            obs.next(new GrpcStatusEvent(error.code, error.message, new GrpcMetadata((error as any).metadata)));
            obs.complete();
          } else {
            obs.next(new GrpcDataEvent(data as any));
          }
        },
      );

resulting object in the obs Observable is { statusCode: 8, statusMessage: "Http response at 400 or 500 level, http status code: 429", metadata: {} } so the code does get parsed, but for some reason in the grpc-web code it does not recognize keep the metadata (or the original message)

Excerpt from grpcwebclientreadablestream.ts

typescript
// There's an XHR level error
      let xhrStatusCode = -1;
      if (lastErrorCode !== ErrorCode.NO_ERROR) {
        switch (lastErrorCode) {
          case ErrorCode.ABORT:
            grpcStatusCode = StatusCode.ABORTED;
            break;
          case ErrorCode.TIMEOUT:
            grpcStatusCode = StatusCode.DEADLINE_EXCEEDED;
            break;
          case ErrorCode.HTTP_ERROR:
            xhrStatusCode = this.xhr!.getStatus();
            grpcStatusCode = fromHttpStatus(xhrStatusCode);
            break;
          default:
            grpcStatusCode = StatusCode.UNAVAILABLE;
        }
        if (grpcStatusCode === StatusCode.ABORTED && this.aborted) {
          return;
        }
        let errorMessage = ErrorCode.getDebugMessage(lastErrorCode);
        if (xhrStatusCode !== -1) {
          errorMessage += `, http status code: ${xhrStatusCode}`;
        }

        this.handleError(new RpcError(grpcStatusCode, errorMessage));
        return;
      }

We use the metadata for the extended/rich status header. Currently we are testing with 429 http responses.