Hmbown/CodeWhale · error · anyhow::Error
The Codewhale service returned an account without an ID
Error message
The Codewhale service returned an account without an ID
What it means
After a successful GET /api/me (HTTP 200, JSON parsed into MeResponse), the CLI validates that user.id is a non-empty trimmed string. An account record without an ID cannot be stored or addressed by later calls, so the response is rejected even though the HTTP call succeeded.
Source
Thrown at crates/cli/src/cloud.rs:382
}
fn save_auth(&self, bundle: AuthBundle) -> Result<()> {
self.account_store
.save(bundle)
.context("failed to save the Codewhale account session in the local secret store")
}
fn clear_auth(&self) -> Result<()> {
self.account_store
.clear()
.context("failed to remove the local Codewhale account session")
}
fn me(&self) -> Result<CloudUser> {
let response = self.execute_authenticated(HttpMethod::Get, "/api/me", None)?;
let me: MeResponse = expect_json(response, &[200])?;
if me.user.id.trim().is_empty() {
bail!("The Codewhale service returned an account without an ID");
}
if let Some(mut stored) = self.load_auth()? {
stored.bundle.user = Some(me.user.clone());
self.save_auth(stored.bundle)?;
}
Ok(me.user)
}
fn set_key(&self, provider: CloudProvider, key: &str, label: &str) -> Result<()> {
let path = format!("/api/model-keys/{}", provider.slug());
let response = self.execute_authenticated(
HttpMethod::Put,
&path,
Some(json_body(&ModelKeyRequest { key, label })?),
)?;
expect_empty(response, &[200, 201])
}
View on GitHub (pinned to 0c42157ee5)
Solutions
- Inspect the raw /api/me response (curl with the stored bearer token) and confirm the user object carries a non-empty id.
- If you run a mock server, make it return a realistic id in the user object.
- If the real service is returning id-less users, report it as a server-side data/regression issue with the response payload.
- Update to matching CLI/service versions in case the field name changed.
Example fix
# mock server before
{"user": {"email": "a@b.c"}}
# mock server after
{"user": {"id": "usr_123", "email": "a@b.c"}} Defensive patterns
Strategy: validation
Validate before calling
// For mock/stub servers: guarantee the me payload shape
fn valid_me_payload(user: &serde_json::Value) -> bool {
user.get("id").and_then(|v| v.as_str()).map(|s| !s.trim().is_empty()).unwrap_or(false)
} Type guard
fn is_valid_cloud_user(v: &serde_json::Value) -> bool {
v.pointer("/user/id")
.and_then(|id| id.as_str())
.map(|s| !s.trim().is_empty())
.unwrap_or(false)
} Try / catch
match client.me().await {
Ok(user) => user,
Err(e) if e.to_string().contains("without an ID") => {
// 200-but-malformed: do not retry; capture raw response and report upstream
report_contract_violation(raw_response).await;
return Err(e);
}
Err(e) => Err(e),
} Prevention
- Make test doubles return realistic user objects with non-empty ids.
- Pin CLI and service versions together in deployments.
- Log raw /api/me bodies when contract errors appear.
When it happens
Trigger: The service returns 200 with a user object whose id field is missing (serde default), empty, or whitespace-only — e.g. malformed backend record, API contract change, or a mock/test server returning {"user": {}}.
Common situations: Developing against a stub /api/me that omits id, service regression that serializes anonymous/null accounts, or a version skew where the field was renamed and serde silently defaults it.
Related errors
- The Codewhale service returned an unexpectedly large respons
- Codewhale account login timed out; run `codewhale account lo
- Not signed in. Run `codewhale account login` first
- The Codewhale account session expired. Run `codewhale accoun
- Codewhale account login requires an OS credential manager fo
AI-assisted analysis of Hmbown/CodeWhale@0c42157ee5 (2026-08-20).
Data as JSON: /api/errors/5a226330e61498e4.
Report an issue: GitHub.