nexu-io/open-design · error · Error

collab cloud is not configured (OD_COLLAB_CLOUD_URL is unset

Error message

collab cloud is not configured (OD_COLLAB_CLOUD_URL is unset)

What it means

Thrown by createCollabCloudClient() when readCollabCloudConfig() returns null, i.e. the env var OD_COLLAB_CLOUD_URL is unset or blank. The collab-cloud module deliberately uses an opt-in, env-scoped config (this file owns OD_COLLAB_CLOUD_*, not app-config.ts) and the client factory treats a missing URL as a hard stop rather than returning a degraded handle. The file header notes callers are expected to degrade with client?.method() no-ops when collab cloud is off.

Source

Thrown at apps/daemon/src/integrations/collab-cloud.ts:72

  displayName: string;
  role: CollabMemberRole;
}

export interface CollabCloudPullResult {
  comments: CollabCloudComment[];
  latestSeq: number;
}

interface CollabCloudClientOptions {
  config?: CollabCloudConfig;
  fetch?: FetchLike;
  timeoutMs?: number;
}

export function createCollabCloudClient(options: CollabCloudClientOptions = {}) {
  const config = options.config ?? readCollabCloudConfig();
  if (!config) {
    throw new Error('collab cloud is not configured (OD_COLLAB_CLOUD_URL is unset)');
  }
  const fetchImpl = options.fetch ?? fetch;
  const timeoutMs = options.timeoutMs ?? DEFAULT_FETCH_TIMEOUT_MS;

  function authHeaders(extra?: Record<string, string>): Record<string, string> {
    const headers: Record<string, string> = { 'content-type': 'application/json', ...extra };
    if (config!.token) headers.authorization = `Bearer ${config!.token}`;
    return headers;
  }

  async function request<T>(
    method: string,
    path: string,
    body?: unknown,
    extraHeaders?: Record<string, string>,
  ): Promise<{ status: number; payload: T; etag: string | null }> {
    const controller = new AbortController();
    const timeout = setTimeout(() => controller.abort(), timeoutMs);

View on GitHub (pinned to 5be4028344)

Solutions

  1. Gate the call site: only build the client when hasExplicitCollabCloudConfig() is true, and otherwise treat collab cloud as a no-op (client?.method()).
  2. Set OD_COLLAB_CLOUD_URL (and optionally OD_COLLAB_CLOUD_TOKEN) in the daemon environment and restart the daemon.
  3. If you need the client in a context without env, pass options.config explicitly: createCollabCloudClient({ config: { baseUrl, token } }).

Example fix

// before
const client = createCollabCloudClient();
await client.registerMember(teamId, memberId, input);

// after
if (!hasExplicitCollabCloudConfig()) return; // off-team no-op
const client = createCollabCloudClient();
await client.registerMember(teamId, memberId, input);
Defensive patterns

Strategy: validation

Validate before calling

import { hasExplicitCollabCloudConfig } from '../integrations/collab-cloud.js';

function shouldUseCollabCloud(env: NodeJS.ProcessEnv = process.env): boolean {
  return hasExplicitCollabCloudConfig(env);
}

// usage
if (!shouldUseCollabCloud()) return; // degrade to no-op
const client = createCollabCloudClient();

Type guard

import type { CollabCloudConfig } from '../integrations/collab-cloud.js';

function isCompleteCollabCloudConfig(c: CollabCloudConfig | null): c is CollabCloudConfig {
  return c !== null && typeof c.baseUrl === 'string' && c.baseUrl.trim().length > 0;
}

Try / catch

try {
  const client = createCollabCloudClient();
} catch (err) {
  if (err instanceof Error && err.message.includes('OD_COLLAB_CLOUD_URL is unset')) {
    // expected when collab cloud is off — degrade silently
    return;
  }
  throw err;
}

Prevention

When it happens

Trigger: Calling createCollabCloudClient() (with no options.config override) while OD_COLLAB_CLOUD_URL is empty/unset in the daemon process environment. Also triggered by a caller that forgets to call hasExplicitCollabCloudConfig() first and unconditionally invokes the factory.

Common situations: Off-team / unconfigured daemon where collab cloud was never enabled; local dev shell that did not export OD_COLLAB_CLOUD_URL; tests that construct the client without injecting options.config; a packaged run that lost the env var because the namespace env was not propagated to the agent subprocess.

Related errors


AI-assisted analysis of nexu-io/open-design@5be4028344 (2026-08-12). Data as JSON: /api/errors/9d277a5b3ee30585. Report an issue: GitHub.