Skip to main content
← Back to list
01Issue
BugClosedSwamp CLITeam
Assigneesstack72

Relationships

#1381 Misleading 'Your collective token lacks the X scope' when scope resolution failed — startup whoami errors are silently swallowed

Opened by magistr · 7/24/2026

Summary

When the CLI cannot determine a collective token's scopes — because the startup whoami to swamp-club.com failed (DNS error, connect failure, timeout, 5xx) — team-feature pre-flights report:

Error: Your collective token lacks the datastore:* scope.

The token actually has the scope. The real (network) error is silently discarded, so the user is sent to swamp-club.com/collectives to re-mint a token that was fine all along. On headless/ephemeral environments this is a day-loser: the same token passes on one machine and "lacks the scope" on another, which reads as a token or server-side scope bug, not the network hiccup it is.

Where (source)

Verified at stable 20260724.175725.0-sha.00d0edb5; still present on current main (10943ef).

  1. src/cli/mod.ts:1337-1380 — startup scope resolution when SWAMP_API_KEY is set: try ~/.config/swamp/scope_cache.json, else live whoami with a 10s AbortSignal. The entire block is wrapped in a bare try { … } catch { /* Best-effort — don't block CLI startup */ } — any thrown error (DNS, TCP, timeout, HTTP 5xx via UserError) is swallowed with no logging, leaving authScopes undefined. Two more silent paths: a 401 makes whoami() return { authenticated: false } so setAuthScopes is never called, and a 200 without a scopes field sets setAuthScopes(undefined).
  2. src/cli/auth_context.ts:85-98requireScope(scope) throws missing_scope ("Your collective token lacks the X scope") whenever collectiveToken === true && authScopes === undefined.
  3. Call sites are pure client-side pre-flights on that in-memory state: datastore_setup.ts:235, vault_create.ts:87 (via the shared helper), serve.ts:962.

Net effect: four unrelated failure modes — network unreachable/timeout, HTTP 5xx, 401, and a 200 missing scopes — all render as the same "lacks the scope" message. Only "200 with scopes that don't include X" genuinely means what the message says.

Deterministic repro

export SWAMP_API_KEY=[REDACTED-SECRET-1]        # valid collective token WITH datastore:* scope
export HOME="$(mktemp -d)"                # fresh: no auth.json, no scope_cache.json
export SWAMP_CLUB_URL=https://[IP-1]:9 # unroutable -> startup whoami fails
swamp datastore setup extension @webframp/postgres-datastore
# -> Error: Your collective token lacks the datastore:* scope.

Unset SWAMP_CLUB_URL (reachable swamp-club.com), same token, same command: passes the pre-flight. Any transient real-world network failure during the 10s window reproduces the same false message — no env override needed.

How we hit it

Headless Firecracker microVM guests authenticating with SWAMP_API_KEY only. Every boot starts with a fresh HOME → empty scope cache → mandatory live whoami through a NAT'd guest network that is occasionally flaky. Result: the token is "rejected" in the guest while the identical bytes pass on the (network-healthy) host — and after the host's first success, scope_cache.json makes host runs zero-network, deepening the false impression that the token itself differs per machine. We rotated/re-minted perfectly good tokens before reading the source.

Expected

  • Distinguish "could not verify scopes" from "verified and missing": e.g. Could not verify your collective token's scopes (whoami: <underlying error>). Retry, or check connectivity to swamp-club.com. with its own error code (scope_unverified), keeping missing_scope for the genuine case.
  • Report a 401 as an authentication failure, not a missing scope.
  • Log the swallowed whoami error (warn/debug) instead of discarding it in the bare catch.
  • Optionally: retry the whoami once at requireScope time when scopes are unresolved, since a single 10s startup attempt is the only shot per invocation.

Context

The scope gate is new: shipped in swamp PR #1934 and hot-fixed the same evening by PR #1936 — whose commit message documents three earlier causes of this exact false "lacks scope" symptom (username guard, --unstable-bundle state duplication, auth.json clobber). This is a fourth, environmental one; the pre-flight seems like a prime candidate for the E2E UAT tracked in Lab #1375.

Workaround we use meanwhile: pre-seed ~/.config/swamp/scope_cache.json with {"fingerprint": "<first 12 chars of the token>", "scopes": ["datastore:*", "vault:*"]} so the pre-flight passes without a live whoami.

Environment

  • swamp stable 20260724.175725.0-sha.00d0edb5 (also inspected main @ 10943ef)
  • Linux x86_64 (microVM guest, fresh HOME per boot) and macOS 14 host
  • Auth: SWAMP_API_KEY collective token (swamp_org_…) minted via swamp auth token create --collective … --scopes datastore:*,vault:*
02Bog Flow
OPENTRIAGEDIN PROGRESSCLOSED+ 1 MOREASSIGNED+ 1 MOREPLANNING

Closed

7/25/2026, 12:27:46 AM

No activity in this phase yet.

03Sludge Pulse
stack72 assigned stack727/24/2026, 9:15:49 PM
Editable. Press Enter to edit.

stack72 commented 7/25/2026, 12:27:46 AM

@magistr Thanks for the detailed reports — we appreciate the work you're putting in to make the tool better. Fixes are in #1960 and will be released shortly.

Sign in to post a ripple.