can1357/oh-my-pi · warning
LSP configuration was superseded during reload: ${config.com
Error message
LSP configuration was superseded during reload: ${config.command} What it means
During LSP client creation, getConfigOrCreate checks whether the client configuration for this key was invalidated by a concurrent reload. If a reload superseded the config while this coroutine was waiting (past the lock check), creating a client from the stale config could launch a server with outdated settings, so the library throws instead.
Source
Thrown at packages/coding-agent/src/lsp/client.ts:963
cwd: string,
initTimeoutMs?: number,
signal?: AbortSignal,
): Promise<LspClient> {
const key = clientKey(config, cwd);
// Check if client already exists
const existingClient = clients.get(key);
if (existingClient && !invalidatedClientKeys.has(key)) {
existingClient.lastActivity = Date.now();
return existingClient;
}
// Check if another coroutine is already creating this client
const existingLock = clientLocks.get(key);
if (existingLock) {
return existingLock.promise;
}
if (invalidatedClientKeys.has(key)) {
throw new Error(`LSP configuration was superseded during reload: ${config.command}`);
}
// Do not start a fresh identity until superseded processes are confirmed stopped.
const reloadBarrier = clientReloadBarriers.get(path.resolve(cwd));
if (reloadBarrier) {
try {
await untilAborted(signal, reloadBarrier);
} catch (error) {
throwIfAborted(signal);
throw error;
}
const clientAfterReload = clients.get(key);
if (clientAfterReload && !invalidatedClientKeys.has(key)) {
clientAfterReload.lastActivity = Date.now();
return clientAfterReload;
}
const lockAfterReload = clientLocks.get(key);
if (lockAfterReload) return lockAfterReload.promise;View on GitHub (pinned to 9690622007)
Solutions
- Retry the operation — the next call will create the client from the fresh config
- Ensure config reloads don't race with first LSP usage (await reload completion before tool calls)
- If it recurs, check for repeated config-watch triggers (e.g. a file being rewritten in a loop)
Example fix
// before: fire tool call immediately after editing config
await updateConfig(); await lspHover(file, pos);
// after: await reload settling, then retry on supersession
await updateConfig(); await lspReloadSettled();
try { await lspHover(file, pos); } catch (e) { if (String(e).includes('superseded')) await lspHover(file, pos); } Defensive patterns
Strategy: retry
Validate before calling
// No public pre-check for internal invalidated keys; best effort is ensuring config is stable if (configWatcher.pendingReload) await configWatcher.settled();
Try / catch
try {
const client = await getConfigOrCreate(config, cwd);
} catch (err) {
if (String(err.message).includes('superseded during reload')) {
await Bun.sleep(50); // let reload finish, then retry with fresh config
return getConfigOrCreate(config, cwd);
}
throw err;
} Prevention
- Await config reload events before issuing LSP-dependent tool calls
- Debounce rapid config edits so reloads don't interleave with startup
- Retry on 'superseded' errors — they are transient race artifacts
When it happens
Trigger: Two concurrent callers race: caller A starts client creation, a config reload invalidates the key (invalidatedClientKeys), then A resumes past the clientLocks check and finds its key invalidated — the throw fires at the pre-lock recheck.
Common situations: Editing LSP server config (command, args) in .omp settings while a first tool call triggers server startup; hot-reloading config during warmup; multiple files opened simultaneously right after a config change.
Related errors
- LSP configuration was superseded during initialization: ${co
- OAuth refresh ownership was lost before persistence
- OAuth credential no longer exists for provider: ${provider}
- No credential with id=${id}
- session header changed during stats cleanup: ${session.path}
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/0db95c2addcfcda1.
Report an issue: GitHub.