mastra-ai/mastra · warning
Broker election in progress by another process
Error message
Broker election in progress by another process
What it means
If the election lock file exists but is NOT stale, another live process is currently running broker election. After a short 150ms wait the process tries to connect as a client; if that fails it throws this error indicating the election is still in progress elsewhere.
Source
Thrown at packages/core/src/events/unix-socket-pubsub.ts:454
*/
async #electBroker(): Promise<void> {
const lockPath = this.socketPath + '.elect';
let lockFd: FileHandle | undefined;
try {
lockFd = await open(lockPath, 'wx');
} catch (e) {
if ((e as NodeJS.ErrnoException).code === 'EEXIST') {
if (await this.#isElectionLockStale(lockPath)) {
await unlink(lockPath).catch(() => {});
throw new Error('Stale broker election lock removed');
}
await new Promise(resolve => setTimeout(resolve, 150));
try {
await this.#connectClient();
this.#throwIfClosed();
return;
} catch {
throw new Error('Broker election in progress by another process');
}
}
throw e;
}
try {
// Re-check: a previous election round may have installed a broker
// between our initial connectClient() and acquiring this lock.
try {
await this.#connectClient();
this.#throwIfClosed();
return;
} catch {
// Still no live broker — proceed with election.
}
await unlink(this.socketPath).catch(() => {});
this.#throwIfClosed();
await this.#listen();View on GitHub (pinned to 75dd419e61)
Solutions
- Retry the publish/subscribe with backoff until the other process finishes election and binds the broker
- Increase startup timeout / retry count around first use
- Investigate why the electing process is slow or whether it died leaving a lock the staleness check considers fresh (e.g. very short staleness window vs clock skew)
- Ensure all processes use the same socket path and have consistent clocks so staleness detection works
Example fix
// before
await pubsub.publish("t", e); // threw during simultaneous startup
// after
let err;
for (let i = 0; i < 5; i++) {
try { await pubsub.publish("t", e); err = null; break; }
catch (e) { err = e; await new Promise(r => setTimeout(r, 200 * (i + 1))); }
}
if (err) throw err; Defensive patterns
Strategy: retry
Validate before calling
// only one process should attempt election first
if (isPrimaryInstance()) {
await pubsub.publish('boot', {}); // triggers/finishes election
}
await waitForBrokerReady(socketPath, { timeoutMs: 5000 }); Try / catch
try {
await pubsub.subscribe(topic, cb);
} catch (e) {
if (e.message === 'Broker election in progress by another process') {
await backoff(attempt); // election resolves shortly; retry
return retry(attempt + 1);
}
throw e;
} Prevention
- Retry with exponential backoff (e.g. 200ms, 400ms, 800ms) during multi-process startup
- Stagger instance startup (readiness gates) so one process elects first
- Investigate slow election in the peer process if retries exhaust
- Ensure lock staleness detection has correct clocks; avoid large clock skew between hosts
When it happens
Trigger: #electBroker (from #start): open(lockPath,'wx') fails with EEXIST, #isElectionLockStale is false, the 150ms-delayed #connectClient attempt fails, so no broker is available yet and the lock is actively held by another process.
Common situations: Many processes starting simultaneously against a fresh socket path, slow election in the peer process (slow disk/loads), retry logic giving up before the other process finishes binding the broker.
Related errors
- Stale broker election lock removed
- SignalsPubSub is closed
- UnixSocketPubSub does not support grouped subscriptions yet
- UnixSocketPubSub is closed
- Factory kickoff run ended in error.
AI-assisted analysis of mastra-ai/mastra@75dd419e61 (2026-08-30).
Data as JSON: /api/errors/77f7f3ba63b78405.
Report an issue: GitHub.