grpc/grpc-go · error

no error details for status with code OK

Error message

no error details for status with code OK

What it means

Returned by (*Status).WithDetails when the receiver Status has code codes.OK. gRPC forbids attaching rich error detail messages to a non-error status, since details are part of the error contract. WithDetails is only meaningful on statuses that represent an actual failure. The guard sits at internal/status/status.go:135-137 and returns a plain errors.New value.

Source

Thrown at internal/status/status.go:136

	if s == nil {
		return nil
	}
	return proto.Clone(s.s).(*spb.Status)
}

// Err returns an immutable error representing s; returns nil if s.Code() is OK.
func (s *Status) Err() error {
	if s.Code() == codes.OK {
		return nil
	}
	return &Error{s: s}
}

// WithDetails returns a new status with the provided details messages appended to the status.
// If any errors are encountered, it returns nil and the first error encountered.
func (s *Status) WithDetails(details ...protoadapt.MessageV1) (*Status, error) {
	if s.Code() == codes.OK {
		return nil, errors.New("no error details for status with code OK")
	}
	// s.Code() != OK implies that s.Proto() != nil.
	p := s.Proto()
	for _, detail := range details {
		m, err := anypb.New(protoadapt.MessageV2Of(detail))
		if err != nil {
			return nil, err
		}
		p.Details = append(p.Details, m)
	}
	return &Status{s: p}, nil
}

// Details returns a slice of details messages attached to the status.
// If a detail cannot be decoded, the error is returned in place of the detail.
// If the detail can be decoded, the proto message returned is of the same
// type that was given to WithDetails().
func (s *Status) Details() []any {

View on GitHub (pinned to 03255a9237)

Solutions

  1. Only call WithDetails when s.Code() != codes.OK; guard with an if before attaching details.
  2. If you genuinely have no error, skip the WithDetails call entirely and return the OK status unchanged.
  3. Use status.New with an explicit failing code (e.g. codes.Internal) before adding details.
  4. Refactor helpers to take a *status.Status and early-return on OK instead of always appending details.

Example fix

// before
st := status.New(codes.OK, "")
newSt, err := st.WithDetails(detail) // returns error

// after
st := status.New(codes.Internal, "boom")
if st.Code() != codes.OK {
    newSt, err = st.WithDetails(detail)
}
Defensive patterns

Strategy: validation

Validate before calling

func safeWithDetails(st *status.Status, details ...protoadapt.MessageV1) (*status.Status, error) {
    if st.Code() == codes.OK {
        return st, nil // nothing to attach
    }
    return st.WithDetails(details...)
}

Type guard

func isErrorStatus(st *status.Status) bool { return st != nil && st.Code() != codes.OK }

Prevention

When it happens

Trigger: Calling status.New(codes.OK, "").WithDetails(detail), or invoking WithDetails on a Status whose code was never changed from the zero value (OK). Also happens when reusing a Status returned from a prior call that resolved to OK and then unconditionally chaining WithDetails.

Common situations: Programmatically building a status and forgetting to set a non-OK code; helper functions that always call WithDetails without checking whether an upstream call actually failed; copying error-detail logic from a failing path into a success path.

Related errors


AI-assisted analysis of grpc/grpc-go@03255a9237 (2026-08-07). Data as JSON: /api/errors/e7d639db318e5ceb. Report an issue: GitHub.