toeverything/AFFiNE · error · UnsupportedClientVersion
unsupported_client_version
unsupported_client_version
Error message
Unsupported client with version [${clientVersion}], required version is [${requiredVersion}]. What it means
Thrown by RealtimeGateway.assertVersion when the clientVersion on a realtime envelope is missing, unparseable, fails semver.valid, or does not satisfy MIN_REALTIME_CLIENT_VERSION (>=0.26.0-0, prereleases included). It blocks all realtime:request/subscribe/unsubscribe traffic from incompatible clients to prevent protocol drift.
Source
Thrown at packages/backend/server/src/core/realtime/gateway.ts:165
@OnEvent('realtime.topic.changed', { suppressError: true })
onRealtimeTopicChanged(payload: RealtimePublishPayload) {
try {
this.publisher.publishLocal(payload);
} catch (error) {
this.logger.error('Failed to publish realtime event', error);
}
}
private assertVersion(clientVersion?: string) {
const normalized = clientVersion
? normalizeRealtimeClientVersion(clientVersion)
: null;
if (
!normalized ||
!semver.valid(normalized) ||
!MIN_REALTIME_CLIENT_VERSION.test(normalized)
) {
throw new UnsupportedClientVersion({
clientVersion: clientVersion ?? 'unset_or_invalid',
requiredVersion: '>=0.26.0',
});
}
}
}
View on GitHub (pinned to 26c515e050)
Solutions
- Upgrade the client to >=0.26.0 and ensure the realtime envelope includes a valid semver clientVersion.
- For canary builds, set env.namespaces.canary and use the canary-date version format.
- If you control the client, send the same version reported to the version guard on /api/version.
- As a last resort on a self-host dev box, downgrade the server or pin a compatible client.
Example fix
// before
socket.emit('realtime:subscribe', { topic, input });
// after
socket.emit('realtime:subscribe', {
clientVersion: APP_VERSION, // e.g. '0.26.0'
topic,
input,
}); Defensive patterns
Strategy: validation
Validate before calling
import semver from 'semver';
const MIN = new semver.Range('>=0.26.0-0', { includePrerelease: true });
function clientOk(v?: string) {
return !!v && semver.valid(v) != null && MIN.test(v);
}
if (!clientOk(APP_VERSION)) {
// block realtime connect; show upgrade required banner
} Type guard
function isSemver(v: string): v is string {
return typeof v === 'string' && semver.valid(v) !== null;
} Try / catch
try {
await socket.connect();
} catch (e) {
if (e?.code === 'unsupported_client_version') {
// show 'please update' UI and stop retrying
return showUpgradeRequired(e.requiredVersion);
}
throw e;
} Prevention
- Embed the client version constant at build time and send it on every realtime envelope.
- For canary builds, ensure env.namespaces.canary is configured on the server.
- Run a version-compatibility smoke test against the server's MIN_REALTIME_CLIENT_VERSION in CI.
When it happens
Trigger: Client connects with clientVersion undefined/empty; canary build not in an allowed canary namespace; client version below 0.26.0; non-semver string passed as clientVersion.
Common situations: Old desktop/electron client pointing at a newer server; embedded webview shipping a stale blocksuite bundle; CI hitting the gateway with a raw socket and no version header; canary build deployed outside the canary namespace.
Related errors
- space_access_denied
- unsupported_client_version
- authentication_required
- unsupported_client_version
- authentication_required
AI-assisted analysis of toeverything/AFFiNE@26c515e050 (2026-08-12).
Data as JSON: /api/errors/ee99cfca97d7dc80.
Report an issue: GitHub.