Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions .changeset/fix-token-storage-error-logging.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
---
"@anthropic/gws": patch
---

Log token cache decryption/parse errors instead of silently swallowing

Previously, `load_from_disk` used four nested `if let Ok` blocks that
silently returned an empty map on any failure. When the encryption key
changed or the cache was corrupted, tokens silently stopped loading and
users were forced to re-authenticate with no explanation.

Now logs specific warnings to stderr for decryption failures, invalid
UTF-8, and JSON parse errors, with a hint to re-authenticate.
38 changes: 30 additions & 8 deletions src/token_storage.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,16 +35,38 @@ impl EncryptedTokenStorage {
}

async fn load_from_disk(&self) -> HashMap<String, TokenInfo> {
if let Ok(data) = tokio::fs::read(&self.file_path).await {
if let Ok(decrypted) = crate::credential_store::decrypt(&data) {
if let Ok(json) = String::from_utf8(decrypted) {
if let Ok(map) = serde_json::from_str(&json) {
return map;
}
}
let data = match tokio::fs::read(&self.file_path).await {
Ok(d) => d,
Err(_) => return HashMap::new(), // File doesn't exist yet — normal on first run
};

let decrypted = match crate::credential_store::decrypt(&data) {
Ok(d) => d,
Err(e) => {
eprintln!(
"warning: failed to decrypt token cache ({}): {e:#}",
self.file_path.display()
);
eprintln!("hint: you may need to re-authenticate with `gws auth login`");
return HashMap::new();
}
};

let json = match String::from_utf8(decrypted) {
Ok(j) => j,
Err(e) => {
eprintln!("warning: token cache contains invalid UTF-8: {e}");
return HashMap::new();
}
};

match serde_json::from_str(&json) {
Ok(map) => map,
Err(e) => {
eprintln!("warning: failed to parse token cache JSON: {e}");
HashMap::new()
}
}
HashMap::new()
}

async fn save_to_disk(&self, map: &HashMap<String, TokenInfo>) -> anyhow::Result<()> {
Expand Down
Loading