laurent22/joplin · warning · Error
Could not check for updates. The server rate limit has been
Error message
Could not check for updates. The server rate limit has been exceeded — this is a temporary issue, please try again later.
What it means
Thrown by handleReleaseResponseError when the GitHub releases API responds 403 or 429 AND the response body contains 'rate limit'. This is GitHub's unauthenticated/low-authenticated rate-limit response; the updater translates it into a user-facing temporary-failure message.
Source
Thrown at packages/app-desktop/utils/checkForUpdatesUtils.ts:145
output.push(r);
}
return output.join('\n');
}
const output: Release = {
version: version,
downloadUrl: downloadUrl,
notes: cleanUpReleaseNotes(fullReleaseNotes),
pageUrl: release.html_url,
prerelease: release.prerelease,
};
return output;
};
export const handleReleaseResponseError = (status: number, responseText: string): never => {
if ((status === 403 || status === 429) && responseText.toLowerCase().includes('rate limit')) {
throw new Error('Could not check for updates. The server rate limit has been exceeded — this is a temporary issue, please try again later.');
}
throw new Error(`Could not check for updates. Please try again later (Error ${status}).`);
};
View on GitHub (pinned to 2654b33620)
Solutions
- Wait and retry later — the limit resets on the hour.
- Authenticate the update-check request (GitHub token) to raise the ceiling if the updater supports it.
- Reduce update-check frequency in settings.
- If behind a shared NAT/CI, use an authenticated proxy or a cached release feed.
Example fix
// before
throw new Error('Could not check for updates. The server rate limit has been exceeded — this is a temporary issue, please try again later.');
// after — include retry hint with reset time if available
throw new Error(_('Could not check for updates. GitHub rate limit exceeded (resets at %s). Please try again later.', rateLimitReset)); Defensive patterns
Strategy: retry
Validate before calling
const maxChecksPerHour = 5;
if (checksThisHour >= maxChecksPerHour) {
// skip this check to avoid hitting the rate limit
return;
}
await checkForUpdates(); Type guard
function isRateLimitStatus(status: number, body: string): boolean {
return (status === 403 || status === 429) && body.toLowerCase().includes('rate limit');
} Try / catch
try {
await checkForUpdates();
} catch (e) {
if (e.message.includes('rate limit')) {
// schedule a retry after the GitHub reset window (~1 hr)
} else throw e;
} Prevention
- Throttle update checks (do not poll on every app launch in quick succession).
- Authenticate the GitHub request to raise the rate ceiling where supported.
- Cache the last-known release and only re-check on a sensible interval.
When it happens
Trigger: checkForUpdates fetches GitHub's releases endpoint; the server returns 403/429 with a body mentioning 'rate limit' (case-insensitive). handleReleaseResponseError matches the condition and throws.
Common situations: Many clients behind one NAT/IP checking updates simultaneously; an unauthenticated request after the 60/hr unauthenticated ceiling; CI/shared environments hammering the API; a proxy returning a 403 with 'rate limit' in its error page.
Related errors
- Could not check for updates. Please try again later (Error $
- Locked notes cannot be opened in an external editor
- Format "${format}" can only be exported to a file
- No notes selected for pdf export
- Only one output directory can be selected
AI-assisted analysis of laurent22/joplin@2654b33620 (2026-08-12).
Data as JSON: /api/errors/ab213f75c05e9f64.
Report an issue: GitHub.