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
- Create a workspace on the server first, then retry the runtime config call
- Re-add the workspace entry to the server config and reload
- 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
- Always provision at least one workspace during server setup
- Verify workspaces exist before scripted runtime config changes
- Don't delete the last workspace without recreating one
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
- invalid_path
- OpenWork server has no workspace matching ${directory}.
- t("providers.no_providers_available")
- Sign in to OpenWork Cloud and choose an organization first.
- `${provider.name} does not have a stored organization creden
AI-assisted analysis of different-ai/openwork@2b7df46e8a (2026-09-01).
Data as JSON: /api/errors/1fcb3056192210b8.
Report an issue: GitHub.