multica-ai/multica · error · ErrCloudPATInvalid
cloud pat invalid
Error message
cloud pat invalid
What it means
Sentinel error ErrCloudPATInvalid in server/internal/auth/cloud_pat.go: the Fleet (cloud) verification endpoint answered definitively that the presented mcn_ personal access token is invalid. Per the doc comment, the Auth/DaemonAuth middlewares map it to HTTP 401. It means the token reached Fleet and was rejected — expired, revoked, or malformed — as opposed to Fleet being unreachable (ErrCloudPATUnavailable, 503).
Source
Thrown at server/internal/auth/cloud_pat.go:82
// cloudPATDefaultTimeout is the per-request HTTP timeout for verify
// calls when the caller doesn't supply an *http.Client. Auth must
// stay snappy: Fleet should answer in tens of milliseconds, and a
// hung verify would block every incoming request behind it. Tighter
// than cloudruntime's 35s because that one proxies arbitrary user
// traffic; this one only ever sees a small JSON exchange.
const cloudPATDefaultTimeout = 5 * time.Second
// Verifier sentinel errors. Callers (the Auth / DaemonAuth middlewares)
// branch on these to map cloud outcomes onto HTTP status codes:
//
// - ErrCloudPATInvalid → 401 (Fleet says token is bad)
// - ErrCloudPATUnavailable → 503 (Fleet unreachable / 5xx)
// - ErrCloudPATNotConfigured → 401 (server has no Fleet URL set; we
// don't reveal that mcn_ is "supported but disabled" — failing
// closed avoids treating misconfigured prod the same as enabled)
var (
ErrCloudPATInvalid = errors.New("cloud pat invalid")
ErrCloudPATUnavailable = errors.New("cloud pat verifier unavailable")
ErrCloudPATNotConfigured = errors.New("cloud pat verifier not configured")
)
// CloudPATIdentity is what a successful verify resolves to. We keep
// only the fields the auth path actually needs:
//
// - OwnerID is the user whose request this is (mapped to X-User-ID).
// - InstanceID / InstanceRecordID are recorded so downstream code can
// correlate the request with a specific cloud node; they are not
// used for authorization today, but stashing them now keeps the
// wire shape stable for callers that later want to assert a
// particular instance binding.
//
// We deliberately drop token_last4, status, issued_at, etc. — those
// are diagnostic fields that don't belong in cached auth state.
type CloudPATIdentity struct {
OwnerID string `json:"o"`View on GitHub (pinned to 2c0912b6ec)
Solutions
- Generate a new PAT in the cloud console and replace the stored credential, then retry.
- Verify the token string was copied whole (no leading/trailing whitespace or shell-quoting artifacts).
- Confirm the Fleet URL configured on the server matches the environment the token was issued in.
- Distinguish from 503/unavailable: a 401 means Fleet answered, so do not retry the same token.
Defensive patterns
Strategy: try-catch
Try / catch
if errors.Is(err, auth.ErrCloudPATInvalid) {
http.Error(w, "cloud token rejected; re-authenticate", http.StatusUnauthorized)
return
} Prevention
- Rotate PATs ahead of expiry and update stored credentials everywhere at once.
- Store tokens verbatim — never re-type them; use copy/paste or secret managers.
- Match the token's Fleet environment with the server's configured Fleet URL.
When it happens
Trigger: Request with an mcn_ PAT that Fleet no longer accepts (revoked in the cloud console, expired); token truncated or with stray whitespace/quotes when pasted; token issued for a different Fleet instance than the configured URL.
Common situations: User rotated their cloud PAT but the server config or CLI still holds the old one; copy/paste damage when storing the token; environment pointing at a different Fleet environment (staging vs prod) than where the token was created.
Related errors
- cloud pat verifier unavailable
- cloud runtime fleet URL is not configured
- get source agent: %w
- list skills: %w
- Invalid desktop runtime config JSON: ${err instanceof Error
AI-assisted analysis of multica-ai/multica@2c0912b6ec (2026-08-15).
Data as JSON: /api/errors/eba9b5771f86c949.
Report an issue: GitHub.