different-ai/openwork · critical
OpenWork server did not report an access token after startup
Error message
OpenWork server did not report an access token after startup.
What it means
assertOpenworkServerReady validates the server-info object returned by the embedded OpenWork server after bootstrapping during Electron main-process startup. After confirming the server is running and reports a baseUrl, it requires at least one access credential — ownerToken or clientToken. If both are null/undefined the server came up unauthenticated/unreportable, so the app throws rather than continue without a usable token.
Source
Thrown at apps/desktop/electron/main.mjs:1381
if (runtimeDisposedForQuit || runtimeDisposeInProgress) return;
runtimeDisposeInProgress = true;
try {
await runtimeManager.dispose().catch(() => undefined);
runtimeDisposedForQuit = true;
} finally {
runtimeDisposeInProgress = false;
}
}
function assertOpenworkServerReady(info) {
if (!info?.running) {
throw new Error("OpenWork server did not stay running after startup.");
}
if (!info.baseUrl) {
throw new Error("OpenWork server did not report a base URL after startup.");
}
if (!info.ownerToken && !info.clientToken) {
throw new Error("OpenWork server did not report an access token after startup.");
}
return info;
}
async function bootRuntimeForSelectedWorkspace() {
if (typeof process.env.OPENWORK_EVAL_FATAL_DESKTOP_BOOTSTRAP_FAILURE === "string") {
throw new Error(process.env.OPENWORK_EVAL_FATAL_DESKTOP_BOOTSTRAP_FAILURE);
}
const list = await workspaceStore.readWorkspaceState();
const selectedId = list.selectedId || list.activeId || list.workspaces[0]?.id || "";
const workspace = selectedId
? list.workspaces.find((entry) => entry?.id === selectedId)
: list.workspaces[0];
const workspaceRoot = String(workspace?.path ?? "").trim();
if (!workspaceRoot || workspace?.workspaceType === "remote") {
return { ok: true, skipped: true, reason: "no-local-workspace" };
}
View on GitHub (pinned to 2b7df46e8a)
Solutions
- Quit the app and clear/reset the userData directory (or the stale server state/token file) so a fresh token can be minted on next launch.
- Ensure no stale openwork-server process is holding the old state file; kill leftover processes and relaunch.
- Check file permissions on the userData path so the main process can read the token written by the server.
- If reproducing in dev, run with a clean BLANK_SLATE/test profile so tokens are provisioned from scratch.
- Update the desktop app and server together if a schema mismatch in server info is suspected.
Example fix
// before: reading server info too early const info = await getOpenworkServerInfo(); assertOpenworkServerReady(info); // after: wait for the server to report tokens before asserting const info = await waitForOpenworkServerInfo((i) => Boolean(i.ownerToken || i.clientToken)); assertOpenworkServerReady(info);
Defensive patterns
Strategy: try-catch
Validate before calling
const ready = info && info.baseUrl && (info.ownerToken || info.clientToken);
if (!ready) throw new Error('server not ready: missing baseUrl or access token'); Type guard
function isServerInfoReady(info) {
return typeof info?.baseUrl === 'string' && info.baseUrl.length > 0 &&
(typeof info.ownerToken === 'string' && info.ownerToken.length > 0 ||
typeof info.clientToken === 'string' && info.clientToken.length > 0);
} Try / catch
try {
const info = await startOpenworkServer();
} catch (err) {
if (err.message.includes('did not report an access token')) {
// clear stale userData/server state and retry bootstrap once
await resetServerState();
return retryBootstrap();
}
throw err;
} Prevention
- Wait for a readiness signal (token present) before consuming server info instead of reading it once.
- Keep server and desktop app versions in lockstep to avoid token-info schema drift.
- Avoid wiping the userData directory while the server is running.
- Log server-info shape (without token values) on bootstrap failure for faster diagnosis.
When it happens
Trigger: The desktop bootstrap collects server info after the embedded openwork-server starts; if info.ownerToken and info.clientToken are both falsy (token file missing, server failed to mint/report a token, IPC returned the IDLE_OPENWORK_SERVER_INFO shape with nulls, or a race read the info before tokens were written), this throw fires at main.mjs:1381.
Common situations: Corrupted or wiped userData/credentials directory (token never persisted), stale server from a previous run occupying the state file, permissions preventing the token file read, server version mismatch writing a different info schema, or reading server info before token provisioning completed.
Related errors
- Electron desktop helper is unavailable: ${command}
- Electron desktop helper is unavailable: ${prop}
- Failed to open browser
- ${result}
- Electron eval relaunch helper is unavailable.
AI-assisted analysis of different-ai/openwork@2b7df46e8a (2026-09-01).
Data as JSON: /api/errors/1c98c71bb3af0bf2.
Report an issue: GitHub.