cloudflare/cloudflared · error

ErrUnauthorized

ErrUnauthorized

Error message

unauthorized

What it means

ErrUnauthorized is a sentinel error in cloudflared's cfapi REST client returned by statusCodeToError when the Cloudflare API responds with HTTP 401 (Unauthorized) or 403 (Forbidden). It means the request was rejected by authentication/authorization before any resource-level work happened.

Source

Thrown at cfapi/base_client.go:24

	"fmt"
	"io"
	"net/http"
	"net/url"
	"strings"
	"time"

	"github.com/pkg/errors"
	"github.com/rs/zerolog"
	"golang.org/x/net/http2"
)

const (
	defaultTimeout  = 15 * time.Second
	jsonContentType = "application/json"
)

var (
	ErrUnauthorized = errors.New("unauthorized")
	ErrBadRequest   = errors.New("incorrect request parameters")
	ErrNotFound     = errors.New("not found")
	ErrAPINoSuccess = errors.New("API call failed")
)

type RESTClient struct {
	baseEndpoints *baseEndpoints
	authToken     string
	userAgent     string
	client        http.Client
	log           *zerolog.Logger
}

type baseEndpoints struct {
	accountLevel  url.URL
	zoneLevel     url.URL
	accountRoutes url.URL
	accountVnets  url.URL

View on GitHub (pinned to 2253eeeb25)

Solutions

  1. Regenerate the API/service token and update the configuration (TUNNEL_TOKEN or credentials file).
  2. Verify the token's policy includes the needed permissions (e.g. Account: Cloudflare Tunnel:Edit).
  3. Check account/zone IDs in the request match the token's account scope.
  4. Retry after confirming clock sync (NTP) if using time-bound tokens.

Example fix

// before
client, err := cfapi.NewRESTClient(..., "stale-token", ...)
// after
client, err := cfapi.NewRESTClient(..., os.Getenv("TUNNEL_API_TOKEN"), ...) // token freshly rotated and scoped
Defensive patterns

Strategy: try-catch

Validate before calling

if os.Getenv("TUNNEL_API_TOKEN") == "" {
    return errors.New("TUNNEL_API_TOKEN must be set before calling the cfapi client")
}

Type guard

import "errors"

func IsUnauthorized(err error) bool {
    return errors.Is(err, ErrUnauthorized)
}

Try / catch

resp, err := client.GetTunnel(ctx, accountID, tunnelID)
if err != nil {
    if errors.Is(err, ErrUnauthorized) {
        // refresh token / re-authenticate before retrying
        return fmt.Errorf("check API token and scopes: %w", err)
    }
    return err
}

Prevention

When it happens

Trigger: Any cfapi REST call (tunnel, VM, config endpoints) where the API token/service token is missing, expired, revoked, or lacks scopes for the endpoint; cloudflared receiving 401/403 from api.cloudflare.com during tunnel management operations.

Common situations: Expired or rotated API tokens left in config, tunnel tokens copied incorrectly, an account whose token lacks the Cloudflare Tunnel edit permission, clock skew invalidating tokens, or hitting an endpoint the token's policy does not cover.

Understand the failure class

Related errors


AI-assisted analysis of cloudflare/cloudflared@2253eeeb25 (2026-09-06). Data as JSON: /api/errors/8a9b19ca17320933. Report an issue: GitHub.