Kuberwastaken/claurst · error
Remote settings: unexpected response shape
Error message
Remote settings: unexpected response shape
What it means
The remote-settings response body parsed neither as the expected RemoteSettingsResponse wrapper object nor as a bare settings object (the parser is deliberately permissive and tries both shapes). The server returned 200 but with a JSON body that fits neither contract.
Solutions
- Log or curl the raw response body to see what the endpoint actually returned
- Confirm the settings endpoint version matches what this client expects
- Fall back to cached/local settings until the server shape is fixed
Defensive patterns
Strategy: fallback
When it happens
Trigger: Thrown at src-rust/crates/core/src/remote_settings.rs:239 when the library encounters an invalid state.
Common situations: See trigger scenarios.
AI-assisted analysis of Kuberwastaken/claurst@b0637c97ec (2026-09-10).
Data as JSON: /api/errors/ee884e3995a7d3a1.
Report an issue: GitHub.
Appendix: source
Thrown at src-rust/crates/core/src/remote_settings.rs:239
anyhow::bail!("Remote settings: not authorized ({})", status);
}
other => {
anyhow::bail!("Remote settings: unexpected status {}", other);
}
}
let body: Value = resp.json().await?;
// Try to parse as the expected response shape, but be permissive —
// accept raw settings object if the wrapper is missing.
let (settings, _checksum) = if let Ok(parsed) =
serde_json::from_value::<RemoteSettingsResponse>(body.clone())
{
(parsed.settings, parsed.checksum)
} else if body.is_object() {
(body, None)
} else {
anyhow::bail!("Remote settings: unexpected response shape");
};
Ok(Some(settings))
}
/// Fetch settings with exponential-backoff retry.
///
/// On success returns the new settings value (or `None` for 304).
/// On failure after all retries, returns the last error.
pub async fn fetch_with_retry(&self, cached_checksum: Option<&str>) -> Result<Option<Value>> {
let mut last_err = anyhow::anyhow!("No attempts made");
for attempt in 1..=(DEFAULT_MAX_RETRIES + 1) {
match self.fetch_once(cached_checksum).await {
Ok(v) => return Ok(v),
Err(e) => {
// Auth errors: don't retry
let msg = e.to_string();
if msg.contains("not authorized") || msg.contains("No authentication") {
View on GitHub (pinned to b0637c97ec)