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

  1. 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.
  2. Ensure no stale openwork-server process is holding the old state file; kill leftover processes and relaunch.
  3. Check file permissions on the userData path so the main process can read the token written by the server.
  4. If reproducing in dev, run with a clean BLANK_SLATE/test profile so tokens are provisioned from scratch.
  5. 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

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


AI-assisted analysis of different-ai/openwork@2b7df46e8a (2026-09-01). Data as JSON: /api/errors/1c98c71bb3af0bf2. Report an issue: GitHub.