pulumi/pulumi · error · ErrUnauthorized

Unauthorized: No credentials provided or are invalid.

Error message

Unauthorized: No credentials provided or are invalid.

What it means

ErrUnauthorized is the Pulumi Cloud backend's sentinel error indicating no valid credentials were presented to the service. Code paths use errors.Is(err, ErrUnauthorized) to detect when login/signup is required.

Source

Thrown at pkg/backend/httpstate/backend.go:80

	"github.com/pulumi/pulumi/sdk/v3/go/common/env"
	"github.com/pulumi/pulumi/sdk/v3/go/common/promise"
	"github.com/pulumi/pulumi/sdk/v3/go/common/resource/config"
	"github.com/pulumi/pulumi/sdk/v3/go/common/slice"
	"github.com/pulumi/pulumi/sdk/v3/go/common/tokens"
	"github.com/pulumi/pulumi/sdk/v3/go/common/util/agentdetect"
	"github.com/pulumi/pulumi/sdk/v3/go/common/util/cmdutil"
	"github.com/pulumi/pulumi/sdk/v3/go/common/util/contract"
	"github.com/pulumi/pulumi/sdk/v3/go/common/util/logging"
	"github.com/pulumi/pulumi/sdk/v3/go/common/util/result"
	"github.com/pulumi/pulumi/sdk/v3/go/common/util/retry"
	"github.com/pulumi/pulumi/sdk/v3/go/common/workspace"
	"github.com/pulumi/pulumi/sdk/v3/go/property"

	"go.opentelemetry.io/otel"
	oteltrace "go.opentelemetry.io/otel/trace"
)

var ErrUnauthorized = errors.New("Unauthorized: No credentials provided or are invalid.")

type agentCredentialUseContextKey struct{}

type agentCredentialUse struct {
	sync.Mutex
	cloudURLs map[string]bool
}

// ContextWithAgentCredentialUse returns a context that tracks shared temporary
// agent credential use for one CLI command.
func ContextWithAgentCredentialUse(ctx context.Context) context.Context {
	return context.WithValue(ctx, agentCredentialUseContextKey{}, &agentCredentialUse{
		cloudURLs: map[string]bool{},
	})
}

func agentCredentialUseFromContext(ctx context.Context) *agentCredentialUse {
	use, _ := ctx.Value(agentCredentialUseContextKey{}).(*agentCredentialUse)

View on GitHub (pinned to 793f7b2e16)

Solutions

  1. Run `pulumi login` to authenticate interactively
  2. Set a valid PULUMI_ACCESS_TOKEN (create one at the Pulumi Cloud console) for headless/CI use
  3. Check the credentials file (~/.pulumi/credentials.json) for stale entries for the cloud URL and re-login
  4. Verify you are pointing at the intended cloud URL (default https://api.pulumi.com)

Example fix

// before (CI)
run: pulumi up
// after
env:
  PULUMI_ACCESS_TOKEN: ${{ secrets.PULUMI_ACCESS_TOKEN }}
run: pulumi up
Defensive patterns

Strategy: fallback

Validate before calling

// Go caller check before using the backend
if os.Getenv("PULUMI_ACCESS_TOKEN") == "" {
	if _, err := os.Stat(filepath.Join(home, ".pulumi", "credentials.json")); err != nil {
		return ErrUnauthorized // prompt for login first
	}
}

Try / catch

_, err := httpstate.New(ctx, d, cloudURL, project, insecure)
if errors.Is(err, backend.ErrUnauthorized) {
	// run `pulumi login` or set PULUMI_ACCESS_TOKEN, then retry
}

Prevention

When it happens

Trigger: Calling httpstate backend operations (login, account validation, agent credential flows) with an empty/invalid/expired PULUMI_ACCESS_TOKEN or no stored credentials for the cloud URL; TestCurrent* and validateStoredAccount paths hit it when the API rejects the token.

Common situations: Never running `pulumi login`; PULUMI_ACCESS_TOKEN env var unset, typo'd, or revoked; token expired on CI machines; switching cloud URLs (PULUMI_CLOUD_URL) where no account is stored.

Understand the failure class

Related errors


AI-assisted analysis of pulumi/pulumi@793f7b2e16 (2026-08-31). Data as JSON: /api/errors/623b3bbe3e94c554. Report an issue: GitHub.