containerd/containerd · error
authorization server did not include a token in the response
Error message
authorization server did not include a token in the response
What it means
ErrNoToken is returned when a registry's token endpoint answered HTTP 200 but the JSON body contains no token/access_token field, so the client has no bearer token to authenticate subsequent requests.
Source
Thrown at core/remotes/docker/auth/fetch.go:38
"context"
"encoding/json"
"errors"
"fmt"
"net/http"
"net/url"
"strings"
"time"
remoteserrors "github.com/containerd/containerd/v2/core/remotes/errors"
"github.com/containerd/containerd/v2/pkg/tracing"
"github.com/containerd/containerd/v2/version"
"github.com/containerd/log"
)
var (
// ErrNoToken is returned if a request is successful but the body does not
// contain an authorization token.
ErrNoToken = errors.New("authorization server did not include a token in the response")
)
// GenerateTokenOptions generates options for fetching a token based on a challenge
func GenerateTokenOptions(ctx context.Context, host, username, secret string, c Challenge) (TokenOptions, error) {
realm, ok := c.Parameters["realm"]
if !ok {
return TokenOptions{}, errors.New("no realm specified for token auth challenge")
}
realmURL, err := url.Parse(realm)
if err != nil {
return TokenOptions{}, fmt.Errorf("invalid token auth challenge realm: %w", err)
}
to := TokenOptions{
Realm: realmURL.String(),
Service: c.Parameters["service"],
Username: username,View on GitHub (pinned to 4246446a2b)
Solutions
- Inspect the raw token endpoint response (curl the realm URL with the same params) and fix the auth server so it returns a token/access_token field
- Check the realm in the WWW-Authenticate challenge points at the correct token service
- Update containerd — newer versions accept access_token as well as token fields
- If a proxy is in the path, verify it isn't mangling or truncating the response body
Example fix
// before: server returns {"expires_in":3600} with no token
// after (server side) ensure response includes token
{"token":"eyJhbGciOi...","expires_in":3600} Defensive patterns
Strategy: try-catch
Validate before calling
// probe the token endpoint before pulling
resp, _ := http.Get(tokenRealmURL)
var body map[string]any
json.NewDecoder(resp.Body).Decode(&body)
if body["token"] == nil && body["access_token"] == nil {
return errors.New("token server returns no token field")
} Try / catch
_, err := auth.FetchToken(ctx, client, to, opts)
if errors.Is(err, auth.ErrNoToken) {
return fmt.Errorf("registry auth server misconfigured (no token in 200 body): %w", err)
} Prevention
- Curl the realm URL to verify the token service returns token/access_token
- Audit proxies/CDNs for response rewriting
- Keep containerd updated for broader token-field compatibility
When it happens
Trigger: Calling FetchToken or FetchTokenWithOAuth against a registry whose token server responds successfully but omits 'token'/'access_token' in the JSON body (e.g. misconfigured token service, error-in-200 responses, non-standard auth servers like some Artifactory/Quay setups).
Common situations: Misconfigured proxy or auth middleware stripping fields; registry returning an HTML/empty body with 200; OAuth device/refresh flows where the server only returns refresh tokens without access_token.
Related errors
- no realm specified for token auth challenge
- authorization failed
- failed to fetch oauth token: %w
- failed to fetch anonymous token: %w
- pushing with mount from %s: %w
AI-assisted analysis of containerd/containerd@4246446a2b (2026-09-02).
Data as JSON: /api/errors/44f06b298408d5a0.
Report an issue: GitHub.