janhq/jan · error · UpdateError
Invalid response from server
Error message
Invalid response from server: {0} What it means
UpdateError::InvalidResponse is returned when the endpoint answered successfully but the response content is semantically invalid — for example an unexpected HTTP body, missing fields, or a status/shape the updater doesn't accept. It renders 'Invalid response from server: <detail>'.
Solutions
- Read the embedded detail to identify which part of the response was invalid
- Fetch the endpoint manually and compare against the expected updater format
- Coordinate with the update-server team on schema changes
- Pin/upgrade the app's updater to a version compatible with the new server format
Example fix
// before
if info.version.is_empty() { return Err(UpdateError::InvalidResponse("missing version".into())); }
// after
match semver::Version::parse(&info.version) {
Ok(_) => {}
Err(e) => return Err(UpdateError::InvalidResponse(format!("bad version '{}': {}", info.version, e))),
} Defensive patterns
Strategy: validation
Validate before calling
const body = await res.json();
if (!body.version || !/^\d+\.\d+\.\d+/.test(body.version)) throw new Error('invalid manifest: bad version'); Type guard
function isValidUpdateManifest(x: unknown): x is { version: string; pub_date: string; platforms: Record<string, unknown> } {
const m = x as any;
return !!m && typeof m.version === 'string' && typeof m.pub_date === 'string' && !!m.platforms;
} Prevention
- Validate every required manifest field after parsing
- Check the response is not an HTML error page despite a 200 status
- Keep server and client manifest schemas in sync (contract tests)
- Use strict deserialization (deny_unknown_fields or explicit checks) to catch drift early
When it happens
Trigger: The updater receives a 200 response whose content fails its post-parse validation checks (e.g. missing version field or wrong content type), and the code constructs InvalidResponse(detail).
Common situations: Server updated its manifest schema; endpoint returns 200 with an HTML login page; load balancer intercepting requests; version string format changed.
Related errors
- HTTP request failed
- All endpoints failed
- Failed to parse update response
- No endpoints configured
- AgentToolsError
AI-assisted analysis of janhq/jan@7205d770c1 (2026-09-17).
Data as JSON: /api/errors/c9860d58307d83e1.
Report an issue: GitHub.
Appendix: 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 7205d770c1)