different-ai/openwork · error · ApiError

workspace_missing

workspace_missing

Error message

At least one workspace is required for engine runtime config

What it means

This 400 workspace_missing error is thrown by resolveEngineRuntimeWorkspace when the server config has no workspaces at all — neither a managed engine workspace nor any fallback entry. Engine runtime configuration endpoints (provider sync, workspace config) need at least one workspace to operate against.

Source

Thrown at apps/server/src/server.ts:318

  const provider = body.provider;
  if (!isRecord(provider)) {
    throw new ApiError(400, "invalid_payload", "provider must be an object");
  }
  for (const [providerId, value] of Object.entries(provider)) {
    if (!providerId.trim()) {
      throw new ApiError(400, "invalid_payload", "provider keys must be non-empty strings");
    }
    if (value !== null && !isRecord(value)) {
      throw new ApiError(400, "invalid_payload", "provider values must be objects or null");
    }
  }
  return provider;
}

function resolveEngineRuntimeWorkspace(config: ServerConfig): WorkspaceInfo {
  const workspace = findManagedEngineWorkspace(config.workspaces) ?? config.workspaces[0];
  if (!workspace) {
    throw new ApiError(400, "workspace_missing", "At least one workspace is required for engine runtime config");
  }
  return workspace;
}

function redactBearerTokens(value: string): string {
  return value.replace(/Bearer\s+\S+/g, "Bearer [redacted]");
}

function redactManagedRuntimeValue(value: unknown, path: string[], insideMcpHeaders: boolean): unknown {
  if (typeof value === "string") return insideMcpHeaders ? "[redacted]" : redactBearerTokens(value);
  if (Array.isArray(value)) {
    return value.map((entry, index) => redactManagedRuntimeValue(entry, [...path, String(index)], insideMcpHeaders));
  }
  if (!isRecord(value)) return value;

  return Object.fromEntries(
    Object.entries(value).map(([key, child]) => {
      const childInsideMcpHeaders = insideMcpHeaders || (path.length === 2 && path[0] === "mcp" && key === "headers");

View on GitHub (pinned to 2b7df46e8a)

Solutions

  1. Create a workspace on the server first, then retry the runtime config call
  2. Re-add the workspace entry to the server config and reload
  3. Check config.workspaces in the server config file for accidental emptying

Example fix

// before
await syncProviders(serverId); // fails: no workspaces
// after
await createWorkspace(serverId, { name: "default" });
await syncProviders(serverId);
Defensive patterns

Strategy: validation

Validate before calling

const ws = await listWorkspaces(serverId);
if (!ws.length) throw new Error("create a workspace before configuring engine runtime");

Try / catch

try {
  await syncCloudProviders(serverId);
} catch (e) {
  if (e.code === "workspace_missing") {
    await createWorkspace(serverId, { name: "default" });
    await syncCloudProviders(serverId);
  } else throw e;
}

Prevention

When it happens

Trigger: Calling cloudProviderSync or the workspace config endpoint on a server whose config.workspaces array is empty — e.g. a freshly provisioned server before any workspace was created, or after all workspaces were deleted.

Common situations: Fresh server setup where workspace creation step was skipped; config file wiped or mis-migrated; a script deleted the last workspace then attempted runtime config changes.

Related errors


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