different-ai/openwork · error

projectDir is required

Error message

projectDir is required

What it means

resolveOpencodeConfigPath computes candidate opencode.json/opencode.jsonc paths for a given scope. For scope 'project', the candidates live under the project directory, so a non-empty projectDir is mandatory. When projectDir is missing, empty, or whitespace-only, the function throws 'projectDir is required' instead of guessing a directory.

Source

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

  }
  const openworkServer = assertOpenworkServerReady(await runtimeManager.openworkServerInfo());
  return { ok: true, skipped: false, engine, openworkServer, workspaceId: bootWorkspace.id ?? null };
}

function ensureRuntimeBootstrap() {
  if (!runtimeBootstrapPromise) {
    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) {

View on GitHub (pinned to 2b7df46e8a)

Solutions

  1. Pass a valid, non-empty absolute projectDir when calling with scope 'project'.
  2. Ensure a workspace/project is selected in the UI before invoking project-scoped config operations.
  3. Guard the caller: resolve the current workspace directory first and reject early if it is empty.
  4. If you truly want user-level config, use scope 'global' instead, which needs no projectDir.

Example fix

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

Strategy: validation

Validate before calling

if (scope === 'project' && (typeof projectDir !== 'string' || projectDir.trim() === '')) {
  throw new Error('select a workspace before reading project config');
}

Type guard

function hasProjectDir(dir) {
  return typeof dir === 'string' && dir.trim().length > 0;
}

Prevention

When it happens

Trigger: Any IPC/renderer call that resolves config paths with scope='project' (e.g. reading/editing project opencode config) while passing projectDir as undefined, null, empty string, or a whitespace-only string.

Common situations: Renderer invoked a config command before a workspace was selected, a workspace object lost its path field, or an API refactor renamed the parameter so the value no longer reaches projectDir.

Understand the failure class

Background: "missing required argument" and "the following required arguments were not provided": what required-argument errors mean and how to fix them — this error's family across 20 libraries.

Related errors


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