janhq/jan · warning · UpdateError
Invalid response from server: {0}
Error message
Invalid response from server: {0} What it means
The InvalidResponse variant of UpdateError is returned when the update endpoint responds with a non-2xx HTTP status code. The error message includes both the status code and the response body text, so you can see the server's error detail. This differs from ParseError (2xx but bad body) and RequestFailed (no response at all).
Source
Thrown at src-tauri/src/core/updater/custom_updater.rs:40
Some(key) => key,
None => "local-dev-test-key-not-for-production",
};
/// Timeout for HTTP requests
const REQUEST_TIMEOUT_SECS: u64 = 30;
#[derive(Debug, Error)]
pub enum UpdateError {
#[error("HTTP request failed: {0}")]
RequestFailed(#[from] reqwest::Error),
#[error("Failed to parse update response: {0}")]
ParseError(String),
#[error("All endpoints failed")]
AllEndpointsFailed,
#[error("Invalid response from server: {0}")]
InvalidResponse(String),
#[error("No endpoints configured")]
NoEndpointsConfigured,
}
/// Update information returned by the update check endpoint
/// Compatible with Tauri's updater format
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct UpdateInfo {
pub version: String,
#[serde(default)]
pub notes: Option<String>,
#[serde(default)]
pub pub_date: Option<String>,
#[serde(default)]
pub platforms: Option<serde_json::Value>,
/// URL to download the updateView on GitHub (pinned to fad3f12a14)
Solutions
- Read the status code and body text in the error message to diagnose the server-side issue.
- If 401/403, verify the JAN_SIGNING_KEY build-time env var matches the server.
- If 429, reduce update check frequency.
- If 5xx, wait and retry — the server is temporarily unavailable.
Example fix
# reproduce the request manually to see server response curl -v -H 'Accept: application/json' \ -H 'User-Agent: Jan/1.0.0 (linux; x86_64)' \ https://apps.jan.ai/update-check
Defensive patterns
Strategy: try-catch
Validate before calling
// In Rust, pre-check endpoint health (simplified)
async fn probe_endpoint(url: &str) -> Result<u16, String> {
let resp = reqwest::Client::builder()
.timeout(Duration::from_secs(5))
.build()
.map_err(|e| e.to_string())?
.get(url)
.send()
.await
.map_err(|e| e.to_string())?;
Ok(resp.status().as_u16())
} Try / catch
Err(UpdateError::InvalidResponse(detail)) => {
log::warn!("Update endpoint returned invalid response: {detail}");
// If it contains '401' or '403', the HMAC key may be wrong
// If it contains '5xx', the server is down — try fallback endpoints
// If it contains '429', back off before retrying
} Prevention
- Log the full InvalidResponse detail (status code + body) for diagnosis.
- If the status is 401/403, verify the JAN_SIGNING_KEY matches the server.
- If the status is 5xx, wait and retry — it is transient.
- If the status is 429, implement backoff to avoid rate limiting.
When it happens
Trigger: Server returns 404 (endpoint path changed). Server returns 401/403 (HMAC signature rejected or IP blocked). Server returns 500/502/503 (server error, gateway timeout, maintenance). Server returns 429 (rate limited). CDN returns a non-2xx cached error.
Common situations: Endpoint URL changed after an infrastructure migration. HMAC signing key mismatch between client and server (JAN_SIGNING_KEY). Rate limiting from too-frequent update checks. Server-side outage or maintenance window. Reverse proxy misconfiguration.
Related errors
- Failed to parse update response: {0}
- HTTP request failed: {0}
- All endpoints failed
- No endpoints configured
- Failed to fetch models from ${provider.provider}: ${result.s
AI-assisted analysis of janhq/jan@fad3f12a14 (2026-08-12).
Data as JSON: /api/errors/c9860d58307d83e1.
Report an issue: GitHub.