{"record":{"id":"0c3626749742debe","repo":"janhq/jan","slug":"all-endpoints-failed","errorCode":null,"errorMessage":"All endpoints failed","messagePattern":"All endpoints failed","errorType":"error_code","errorClass":"UpdateError","httpStatus":null,"severity":"error","filePath":"src-tauri/src/core/updater/custom_updater.rs","lineNumber":37,"sourceCode":"/// - In CI: Set JAN_SIGNING_KEY environment variable at build time\n/// - In local dev: Falls back to a test key\npub(crate) const SECRET_KEY: &str = match option_env!(\"JAN_SIGNING_KEY\") {\n    Some(key) => key,\n    None => \"local-dev-test-key-not-for-production\",\n};\n\n/// Timeout for HTTP requests\nconst REQUEST_TIMEOUT_SECS: u64 = 30;\n\n#[derive(Debug, Error)]\npub enum UpdateError {\n    #[error(\"HTTP request failed: {0}\")]\n    RequestFailed(#[from] reqwest::Error),\n\n    #[error(\"Failed to parse update response: {0}\")]\n    ParseError(String),\n\n    #[error(\"All endpoints failed\")]\n    AllEndpointsFailed,\n\n    #[error(\"Invalid response from server: {0}\")]\n    InvalidResponse(String),\n\n    #[error(\"No endpoints configured\")]\n    NoEndpointsConfigured,\n}\n\n/// Update information returned by the update check endpoint\n/// Compatible with Tauri's updater format\n#[derive(Debug, Clone, Serialize, Deserialize)]\npub struct UpdateInfo {\n    pub version: String,\n    #[serde(default)]\n    pub notes: Option<String>,\n    #[serde(default)]\n    pub pub_date: Option<String>,","sourceCodeStart":19,"sourceCodeEnd":55,"githubUrl":"https://github.com/janhq/jan/blob/7205d770c1e097c3daf35a911176410e93bc5564/src-tauri/src/core/updater/custom_updater.rs#L19-L55","documentation":"UpdateError::AllEndpointsFailed is the terminal error of the custom updater's fallback loop: every configured update endpoint was tried and each failed (network error, parse error, or invalid response). It carries no payload and renders exactly 'All endpoints failed'.","triggerScenarios":"update_check iterates the configured endpoint list; after the last endpoint returns an error, instead of returning the last cause it collapses into AllEndpointsFailed.","commonSituations":"All update mirrors offline or firewalled; endpoints list misconfigured with wrong hosts; DNS or proxy failures affecting every host; certificate expiry across mirrors.","solutions":["Check connectivity to each configured update endpoint individually","Verify the endpoints list contains correct, reachable URLs","Improve diagnosability by logging/propagating the last per-endpoint error instead of collapsing","Add a working fallback endpoint to the configuration"],"exampleFix":"// before\nreturn Err(UpdateError::AllEndpointsFailed);\n// after\nreturn Err(UpdateError::AllEndpointsFailed); // also log last_err per endpoint for diagnosis","handlingStrategy":"fallback","validationCode":"// pre-check all endpoints before running the update loop\nfor (const ep of endpoints) {\n  const ok = await fetch(ep, { method: 'HEAD' }).then(r => r.ok).catch(() => false);\n  if (ok) break;\n}\n","typeGuard":null,"tryCatchPattern":"match updater.check() {\n    Err(UpdateError::AllEndpointsFailed) => {\n        // notify user all mirrors unreachable; schedule background retry\n    }\n    other => other?,\n}","preventionTips":["Keep several geographically/mirrored endpoints configured","Log each endpoint's individual failure for diagnosis","Monitor update-server uptime","Do not collapse all per-endpoint errors into the aggregate variant in logs"],"tags":["network","updater","fallback-exhausted","rust"],"backgroundTag":"http-request-failed","analyzedSha":"7205d770c1e097c3daf35a911176410e93bc5564","analyzedAt":"2026-09-17T14:27:30.100Z","contentChangedAt":"2026-09-17T14:27:30.100Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}