different-ai/openwork · error

scope must be 'project' or 'global'

Error message

scope must be 'project' or 'global'

What it means

resolveOpencodeConfigPath only accepts scope values 'project' or 'global'; anything else falls into the final else and throws. This is an explicit argument validation to prevent silently resolving config in an unintended location.

Source

Thrown at apps/desktop/electron/main.mjs:1468

    runtimeBootstrapPromise = bootRuntimeForSelectedWorkspace().catch((error) => ({
      ok: false,
      error: error instanceof Error ? error.message : String(error),
    }));
  }
  return runtimeBootstrapPromise;
}

function resolveOpencodeConfigPath(scope, projectDir) {
  if (scope === "project") {
    if (!String(projectDir ?? "").trim()) {
      throw new Error("projectDir is required");
    }
    return workspaceOpencodeConfigCandidates(projectDir);
  } else if (scope === "global") {
    const root = globalOpencodeRoot();
    return [path.join(root, "opencode.jsonc"), path.join(root, "opencode.json")];
  } else {
    throw new Error("scope must be 'project' or 'global'");
  }
}

async function selectOpencodeConfigPath(candidates) {
  for (const candidate of candidates) {
    if (await pathExists(candidate)) return candidate;
  }
  return candidates[0];
}

async function readOpencodeConfig(scope, projectDir) {
  const chosenPath = await selectOpencodeConfigPath(resolveOpencodeConfigPath(scope, projectDir));
  const exists = await pathExists(chosenPath);
  return {
    path: chosenPath,
    exists,
    content: exists ? await readFile(chosenPath, "utf8") : null,
  };

View on GitHub (pinned to 2b7df46e8a)

Solutions

  1. Change scope to exactly 'project' or 'global' (lowercase).
  2. If the call came from commands-style code using 'workspace', switch it to 'project' for config APIs.
  3. Validate/normalize the scope string at the call site before invoking.
  4. Use a union type or constant enum for scope in renderer code so invalid values fail at compile time.

Example fix

// before
await resolveOpencodeConfigPath("workspace", dir);
// after
await resolveOpencodeConfigPath("project", dir);
Defensive patterns

Strategy: validation

Validate before calling

const VALID_CONFIG_SCOPES = ['project', 'global'];
if (!VALID_CONFIG_SCOPES.includes(scope)) {
  throw new Error(`scope must be one of ${VALID_CONFIG_SCOPES.join(', ')}, got ${scope}`);
}

Type guard

function isConfigScope(scope) {
  return scope === 'project' || scope === 'global';
}

Prevention

When it happens

Trigger: Calling a config-path API with scope misspelled ('Project', 'workspace', 'user'), undefined/null scope, or a scope value carried over from the commands API which uses 'workspace' instead of 'project'.

Common situations: Copy-pasting code between the commands API (scope 'workspace'|'global') and the config API (scope 'project'|'global'), typos in string literals, or dynamic scope values derived from unvalidated settings.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


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