nexu-io/open-design · error · Error
workspaceId is required
Error message
workspaceId is required
What it means
Thrown by createActiveWorkspaceSelectionStore.set when the workspaceId argument trims to empty. The store persists the active workspace selection to <dataDir>/workspace-selection.json and refuses to write a blank id, since that would corrupt the selection state and confuse the generation-tracked subscribers. This is a programmatic API, not a CLI flag error — it is hit by route handlers or migrations calling `.set()`.
Source
Thrown at apps/daemon/src/collab/active-workspace-selection.ts:89
const notify = (workspaceId: string | null) => {
for (const listener of listeners) {
try {
listener(workspaceId);
} catch {
// Selection persistence must not fail because one observer did.
}
}
};
return {
get: read,
snapshot() {
return { workspaceId: read(), generation };
},
async set(workspaceId: string) {
const next = workspaceId.trim();
if (!next) throw new Error('workspaceId is required');
cached = next;
generation += 1;
await fs.promises.mkdir(path.dirname(filePath), { recursive: true });
await fs.promises.writeFile(
filePath,
JSON.stringify({ workspaceId: next }, null, 2),
'utf8',
);
notify(next);
},
async clear() {
cached = null;
generation += 1;
await fs.promises.rm(filePath, { force: true });
notify(null);
},
subscribe(listener) {
listeners.add(listener);View on GitHub (pinned to 5be4028344)
Solutions
- Validate the workspace id is non-empty before calling set(): `if (!id?.trim()) return;`.
- Use store.clear() instead of set('') when you intend to remove the selection.
- Trace the caller to ensure the id originates from an authoritative directory lookup, not a raw header.
Example fix
// before await selectionStore.set(req.body.workspaceId); // after const id = req.body.workspaceId?.trim(); if (!id) return; // or call selectionStore.clear() await selectionStore.set(id);
Defensive patterns
Strategy: validation
Validate before calling
async function safeSetWorkspaceSelection(store, workspaceId) {
const next = workspaceId?.trim();
if (!next) return; // or: await store.clear();
await store.set(next);
} Try / catch
try {
await selectionStore.set(workspaceId);
} catch (err) {
if (err instanceof Error && /workspaceId is required/.test(err.message)) {
await selectionStore.clear(); // intent was likely to clear
return;
}
throw err;
} Prevention
- Always trim and check the id at the call site before set().
- Use clear() to remove the selection; never set('') to mean clear.
- Source the id from an authoritative directory lookup, not a raw header.
When it happens
Trigger: A caller invoking `store.set('')`, `store.set(' ')`, or `store.set(someVariable)` where the variable is undefined/empty after trimming.
Common situations: A route passing an unvalidated request body field, a migration reading a stale/empty record, or a refactor that drops the trim guard upstream.
Related errors
- authorized pull receipt has invalid ${key}
- authorized pull response must be an object
- WORKSPACE_PROJECT_PERMISSION_DENIED
- Project ${projectId} not found
- invalid JSON in ${filePath}: ${message}
AI-assisted analysis of nexu-io/open-design@5be4028344 (2026-08-12).
Data as JSON: /api/errors/51ce649b57323c6d.
Report an issue: GitHub.