Summary#
auth status reports ✓ Authenticated but commands that require auth (e.g. issue list, pr list) fail with ✗ Not authenticated. Run "tangled auth login" first. This gives the false impression that no session exists when in fact the session token has simply expired.
Root Cause#
There are two separate mechanisms for authentication:
-
auth statusreads only the metadata file (~/.config/tangled/session.json) — it does not validate the actual session token from the keychain. So it can show "Authenticated" even with an expired session. -
ensureAuthenticated()callsclient.resumeSession(), which callsthis.agent.resumeSession(sessionData)on the AT Protocol agent. If that call fails (e.g. the refresh token has expired and the PDS rejects it), the error is caught atapi-client.ts:109:
} catch (error) {
if (error instanceof KeychainAccessError) throw error;
// Session resume failed (network error, expired refresh token, etc.)
return false; // ← silently swallows the real error
}
This causes ensureAuthenticated to exit with the generic "Not authenticated" message, which is indistinguishable from "you have never logged in."
Diagnostic Evidence#
- Keychain entry exists:
acct=did:plc:b2mcbcamkwyznc5fkplwlxbf, last modified2026-02-11T19:07:00Z - Metadata file exists at
~/.config/tangled/session.json,lastUsed: 2/11/2026 12:23 PM auth status→✓ Authenticated(reads metadata only)issue list→✗ Not authenticated. Run "tangled auth login" first.(resumeSession failed silently)
Proposed Fix#
When resumeSession() returns false in ensureAuthenticated, check whether session metadata exists to distinguish between the two cases:
- No metadata (truly never logged in):
✗ Not authenticated. Run "tangled auth login" first. - Metadata exists but resume failed (expired token):
✗ Session expired. Run "tangled auth login" to re-authenticate.
Optionally, the catch block in resumeSession() could log the underlying error at a debug level so it can be surfaced with a --verbose flag.