temporalio/temporal · error

unexpected response status: %q

Error message

unexpected response status: %q

What it means

httpStatusCodeToHandlerErrorType maps HTTP response statuses from a Nexus handler endpoint onto nexus.HandlerErrorType values. When the server returns a status code that has no mapping (not 4xx/5xx cases like 501, 503, or the upstream-timeout status), it returns this error because the SDK cannot classify the failure. It signals an unanticipated response from the peer, not a domain error.

Source

Thrown at common/nexus/nexusrpc/client.go:450

		return nexus.HandlerErrorTypeConflict, nil
	case http.StatusUnauthorized:
		return nexus.HandlerErrorTypeUnauthenticated, nil
	case http.StatusForbidden:
		return nexus.HandlerErrorTypeUnauthorized, nil
	case http.StatusNotFound:
		return nexus.HandlerErrorTypeNotFound, nil
	case http.StatusTooManyRequests:
		return nexus.HandlerErrorTypeResourceExhausted, nil
	case http.StatusInternalServerError:
		return nexus.HandlerErrorTypeInternal, nil
	case http.StatusNotImplemented:
		return nexus.HandlerErrorTypeNotImplemented, nil
	case http.StatusServiceUnavailable:
		return nexus.HandlerErrorTypeUnavailable, nil
	case nexus.StatusUpstreamTimeout:
		return nexus.HandlerErrorTypeUpstreamTimeout, nil
	default:
		return "", fmt.Errorf("unexpected response status: %q", response.Status)
	}
}

func retryBehaviorFromHeader(header http.Header) nexus.HandlerErrorRetryBehavior {
	switch strings.ToLower(header.Get(headerRetryable)) {
	case "true":
		return nexus.HandlerErrorRetryBehaviorRetryable
	case "false":
		return nexus.HandlerErrorRetryBehaviorNonRetryable
	default:
		return nexus.HandlerErrorRetryBehaviorUnspecified
	}
}

func getUnsuccessfulStateFromHeader(response *http.Response, body []byte) (nexus.OperationState, error) {
	state := nexus.OperationState(response.Header.Get(headerOperationState))
	switch state {
	case nexus.OperationStateCanceled, nexus.OperationStateFailed:

View on GitHub (pinned to bde624efd1)

Solutions

  1. Inspect the wrapped status in the error message and check server/proxy logs to find why that status was returned.
  2. Verify the Nexus endpoint URL, routing, and authentication so requests reach the actual handler instead of a proxy error page.
  3. Fix the server to return proper nexus.HandlerError failures (e.g. Unavailable, NotSupported) instead of raw HTTP errors like 500.
  4. If the status is a valid new Nexus status, upgrade the client SDK to a version that maps it.

Example fix

// before
if resp.StatusCode == http.StatusInternalServerError { /* client has no mapping -> error */ }
// after
// server side: return a proper handler failure instead of a bare 500
return nil, nexus.HandlerErrorf(nexus.HandlerErrorTypeInternal, "operation failed: %v", cause)
Defensive patterns

Strategy: try-catch

Validate before calling

// Peek at endpoint health before calling operations
resp, err := http.Get(endpointURL)
if err == nil && (resp.StatusCode < 200 || resp.StatusCode > 299) && resp.StatusCode != http.StatusServiceUnavailable {
    log.Printf("endpoint returned unmapped status %d; check proxy/auth", resp.StatusCode)
}

Try / catch

result, err := client.ExecuteOperation(ctx, svc, op, input)
var statusErr *errors.StatusError // or inspect wrapped error string
if err != nil {
    if strings.Contains(err.Error(), "unexpected response status") {
        // unclassified peer/proxy failure: log raw status, decide retry vs abort
        return fmt.Errorf("nexus endpoint misbehaving: %w", err)
    }
    return err
}

Prevention

When it happens

Trigger: Calling a Nexus operation via the nexusrpc client when the HTTP handler (or an intermediary proxy/gateway) returns an unmapped status code, e.g. 400, 401, 404, 500, 502, or a nonstandard status, inside defaultErrorFromResponse.

Common situations: A reverse proxy or API gateway intercepting the request and returning 401/404/502; a misconfigured Nexus endpoint URL; a server-side bug returning 500 instead of a Nexus failure; a newer server returning statuses the older client SDK does not know.

Related errors


AI-assisted analysis of temporalio/temporal@bde624efd1 (2026-09-01). Data as JSON: /api/errors/ef868885c6805a85. Report an issue: GitHub.