fix: report version check failures instead of claiming latest (#29626)

GET /api/version/updates returned the running version as latest whenever
the GitHub request failed, so an instance that cannot reach GitHub
reported itself up to date however far behind it was. The exception was
logged at debug, below the default level, so nothing recorded that the
check never happened.

The failure path now returns latest: None and logs at warning.

A null latest cannot be passed to compareVersion as it stood.
current.localeCompare(null) coerces to the string "null", and "0.10.2"
sorts before it, so the function returned true. The backend change alone
would have turned a false (latest) into a false update-available plus a
toast, so the guard is part of the fix.

The three callers stop substituting the running version in their catch,
and the two badge surfaces gain a third state. When latest is unknown
the badge is plain text, since there is no release to link to.

Admin Settings > General was wrong in a worse way than reported: it
initialised updateAvailable false with latest set to the running
version, and never checked on mount, so it claimed (latest) having made
no request at all. It now matches About.svelte, which starts unknown and
checks on mount.

Closes #29580
This commit is contained in:
G30 2026-09-04 11:39:52 -04:00 committed by GitHub
parent c7cce962d2
commit cc14f3dac0
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 45 additions and 30 deletions

View file

@ -2575,8 +2575,8 @@ async def get_app_latest_release_version(user=Depends(get_verified_user)):
return {'current': VERSION, 'latest': latest_version[1:]}
except Exception as e:
log.debug(e)
return {'current': VERSION, 'latest': VERSION}
log.warning(f'Version update check failed: {e}')
return {'current': VERSION, 'latest': None}
@app.get('/api/changelog')

View file

@ -27,10 +27,10 @@
export let saveHandler: Function;
let updateAvailable: boolean | null = false;
let updateAvailable: boolean | null = null;
let version = {
current: WEBUI_VERSION,
latest: WEBUI_VERSION
latest: ''
};
let adminConfig: any = null;
@ -47,7 +47,7 @@
version = await getVersionUpdates(localStorage.token).catch((error) => {
return {
current: WEBUI_VERSION,
latest: WEBUI_VERSION
latest: null
};
});
@ -91,6 +91,10 @@
defaultInterfaceSettings = getDefaultInterfaceSettings();
banners = [...$_banners];
if ($config?.features?.enable_version_update_check) {
checkForVersionUpdates();
}
});
</script>
@ -112,17 +116,23 @@
<Tooltip content={WEBUI_BUILD_HASH}>v{WEBUI_VERSION}</Tooltip>
{#if $config?.features?.enable_version_update_check}
<a
href="https://github.com/open-webui/open-webui/releases/tag/v{version.latest}"
target="_blank"
class="text-gray-500 hover:text-gray-700 dark:text-gray-500 dark:hover:text-gray-300"
>
{updateAvailable === null
? $i18n.t('Checking for updates...')
: updateAvailable
? `(v${version.latest} ${$i18n.t('available!')})`
: $i18n.t('(latest)')}
</a>
{#if version.latest === null}
<span class="text-gray-500 dark:text-gray-500"
>{$i18n.t('Could not check for updates')}</span
>
{:else}
<a
href="https://github.com/open-webui/open-webui/releases/tag/v{version.latest}"
target="_blank"
class="text-gray-500 hover:text-gray-700 dark:text-gray-500 dark:hover:text-gray-300"
>
{updateAvailable === null
? $i18n.t('Checking for updates...')
: updateAvailable
? `(v${version.latest} ${$i18n.t('available!')})`
: $i18n.t('(latest)')}
</a>
{/if}
{/if}
</div>

View file

@ -27,7 +27,7 @@
version = await getVersionUpdates(localStorage.token).catch((error) => {
return {
current: WEBUI_VERSION,
latest: WEBUI_VERSION
latest: null
};
});
@ -66,21 +66,25 @@
</Tooltip>
{#if $config?.features?.enable_version_update_check}
<a
href="https://github.com/open-webui/open-webui/releases/tag/v{version.latest}"
target="_blank"
>
{updateAvailable === null
? $i18n.t('Checking for updates...')
: updateAvailable
? `(v${version.latest} ${$i18n.t('available!')})`
: $i18n.t('(latest)')}
</a>
{#if version.latest === null}
<span>{$i18n.t('Could not check for updates')}</span>
{:else}
<a
href="https://github.com/open-webui/open-webui/releases/tag/v{version.latest}"
target="_blank"
>
{updateAvailable === null
? $i18n.t('Checking for updates...')
: updateAvailable
? `(v${version.latest} ${$i18n.t('available!')})`
: $i18n.t('(latest)')}
</a>
{/if}
{/if}
</div>
<button
class={actionButtonClass}
class="self-start {actionButtonClass}"
on:click={() => {
showChangelog.set(true);
}}

View file

@ -691,6 +691,7 @@
"Copying to clipboard was successful!": "",
"Copyright (c)": "",
"CORS must be properly configured by the provider to allow requests from Open WebUI.": "",
"Could not check for updates": "",
"Could not load release notes.": "",
"Could not read file.": "",
"Couldn't find your language?": "",

View file

@ -658,7 +658,7 @@ export const copyToClipboard = async (text, html = null, formatted = false) => {
};
export const compareVersion = (latest, current) => {
return current === '0.0.0'
return !latest || current === '0.0.0'
? false
: current.localeCompare(latest, undefined, {
numeric: true,

View file

@ -446,7 +446,7 @@
version = await getVersionUpdates(localStorage.token).catch((error) => {
return {
current: WEBUI_VERSION,
latest: WEBUI_VERSION
latest: null
};
});
};