jaegertracing/jaeger · error
malformed token: multiple tokens found
Error message
malformed token: multiple tokens found
What it means
ValidTokenFromGRPCMetadata returns this error when the gRPC metadata contains more than one value under the authorization/bearer header. A single bearer token is expected; multiple values indicate a malformed or conflicting auth header set.
Source
Thrown at internal/auth/bearertoken/grpc.go:37
}
func (tss *tokenatedServerStream) Context() context.Context {
return tss.context
}
// extract bearer token from the metadata
func ValidTokenFromGRPCMetadata(ctx context.Context, bearerHeader string) (string, error) {
md, ok := metadata.FromIncomingContext(ctx)
if !ok {
return "", nil
}
tokens := md.Get(bearerHeader)
if len(tokens) < 1 {
return "", nil
}
if len(tokens) > 1 {
return "", errors.New("malformed token: multiple tokens found")
}
return tokens[0], nil
}
// NewStreamServerInterceptor creates a new stream interceptor that injects the bearer token into the context if available.
func NewStreamServerInterceptor() grpc.StreamServerInterceptor {
return func(srv any, ss grpc.ServerStream, _ *grpc.StreamServerInfo, handler grpc.StreamHandler) error {
if token, _ := GetBearerToken(ss.Context()); token != "" {
return handler(srv, ss)
}
bearerToken, err := ValidTokenFromGRPCMetadata(ss.Context(), Key)
if err != nil {
return err
}
return handler(srv, &tokenatedServerStream{
ServerStream: ss,View on GitHub (pinned to 806f444784)
Solutions
- Ensure the client sets the authorization metadata key exactly once per request (overwrite, not append)
- Fix gateway/proxy config that duplicates the Authorization header into gRPC metadata
- Replace with `md.Set(bearerHeader, token)` instead of `md.Append` when injecting tokens in interceptors
Example fix
// before
md.Append("authorization", "Bearer "+token)
// after
md.Set("authorization", "Bearer "+token) Defensive patterns
Strategy: validation
Validate before calling
md, _ := metadata.FromIncomingContext(ctx)
vals := md.Get("authorization")
if len(vals) > 1 {
return errors.New("authorization metadata set more than once")
} Type guard
func singleToken(md metadata.MD, key string) (string, bool) {
v := md.Get(key)
if len(v) != 1 {
return "", false
}
return v[0], true
} Try / catch
token, err := bearertoken.ValidTokenFromGRPCMetadata(ctx)
if err != nil {
if strings.Contains(err.Error(), "multiple tokens found") {
return status.Error(codes.InvalidArgument, "duplicate authorization metadata")
}
return status.Error(codes.Unauthenticated, err.Error())
} Prevention
- Use md.Set (not md.Append) when injecting auth metadata
- Check middleware chains for double injection
- Verify gateways map Authorization headers one-to-one
When it happens
Trigger: A client (or proxy/metadata forwarding) sends the bearerHeader metadata key twice, e.g. attaching authorization metadata both manually and via an interceptor; md.Get returns len(tokens) > 1 and the function errors.
Common situations: Composed interceptors that each inject the token into the same metadata key; HTTP-to-gRPC gateways duplicating the Authorization header into metadata; middleware that appends instead of replacing.
Understand the failure class
- Parsing and encoding errors: unexpected token, malformed input — why parsers reject input and how to find the real culprit.
Related errors
- access denied
- no http.RoundTripper provided
- authenticator is not supported
- could not create jaeger-query: %w
- no sampling strategy provider specified, expecting 'adaptive
AI-assisted analysis of jaegertracing/jaeger@806f444784 (2026-09-01).
Data as JSON: /api/errors/68fc6355786140e1.
Report an issue: GitHub.