different-ai/openwork · error

Archive is missing .opencode config

Error message

Archive is missing .opencode config

What it means

After extracting all eligible entries from a workspace archive, importWorkspaceConfig verifies that a .opencode directory exists under targetDir. An archive can be a structurally valid ZIP yet contain no .opencode/ files (or only opencode.json), meaning it would not yield a usable OpenWork workspace config, so the import aborts.

Source

Thrown at apps/desktop/electron/workspace-archive.mjs:308

    if (!(await isDirectoryEmpty(targetDir))) throw new Error("Target folder must be empty");
  }
  await mkdir(targetDir, { recursive: true });

  const archiveStats = await stat(archivePath);
  if (archiveStats.size > MAX_ARCHIVE_BYTES) throw new Error("Workspace archive is too large.");
  const buffer = await readFile(archivePath);
  for (const entry of listZipEntries(buffer)) {
    if (entry.name === "manifest.json" || entry.name.endsWith("/")) continue;
    if (!isSafeArchivePath(entry.name)) throw new Error("Archive contains an unsafe path");
    if (!(entry.name === "opencode.json" || entry.name.startsWith(".opencode/"))) continue;
    if (isSecretName(path.basename(entry.name))) continue;
    const outPath = path.join(targetDir, ...entry.name.split("/"));
    await mkdir(path.dirname(outPath), { recursive: true });
    await writeFile(outPath, readZipEntryData(buffer, entry));
  }

  const opencodeDir = path.join(targetDir, ".opencode");
  if (!(await pathExists(opencodeDir))) throw new Error("Archive is missing .opencode config");

  const openworkPath = path.join(opencodeDir, "openwork.json");
  let preset = "starter";
  let workspaceName = typeof name === "string" && name.trim() ? name.trim() : null;

  if (await pathExists(openworkPath)) {
    const raw = await readFile(openworkPath, "utf8");
    try {
      const config = JSON.parse(raw);
      config.authorizedRoots = [targetDir];
      if (!workspaceName && typeof config.workspace?.name === "string" && config.workspace.name.trim()) {
        workspaceName = config.workspace.name.trim();
      }
      if (typeof config.workspace?.preset === "string" && config.workspace.preset.trim()) {
        preset = config.workspace.preset.trim();
      }
      await writeFile(openworkPath, `${JSON.stringify(config, null, 2)}\n`, "utf8");
    } catch {

View on GitHub (pinned to 2b7df46e8a)

Solutions

  1. Repack the archive so it contains .opencode/ entries at the archive root (at least one non-secret file under .opencode/).
  2. Re-export with exportWorkspaceConfig from an existing workspace instead of zipping manually.
  3. Verify you are importing the right archive and that the zip root is the workspace folder, not its parent.

Example fix

// before: zip -r workspace.zip ./my-project  -> entries 'my-project/.opencode/...'
// after: run from inside the workspace root
zip -r workspace.zip opencode.json .opencode/
Defensive patterns

Strategy: validation

Validate before calling

import { readFile } from "node:fs/promises";
import { listZipEntries } from "./workspace-archive.mjs";
async function archiveHasOpencodeConfig(archivePath) {
  const buffer = await readFile(archivePath);
  return listZipEntries(buffer).some(
    (e) => e.name === "opencode.json" || e.name.startsWith(".opencode/"),
  );
}

Try / catch

try {
  await importWorkspaceConfig({ archivePath, targetDir });
} catch (err) {
  if (err.message === "Archive is missing .opencode config") {
    // prompt user for a valid workspace archive
  } else throw err;
}

Prevention

When it happens

Trigger: Calling importWorkspaceConfig with an archive that contains no files under '.opencode/' — e.g. only manifest.json and opencode.json, or an archive of the wrong folder entirely.

Common situations: Hand-built archives zipped from the wrong directory; archives where .opencode entries were skipped because names matched secret-name filters; zipping the parent folder so entries are 'myproject/.opencode/...' with no top-level .opencode files.

Understand the failure class

Background: "X is required", "must be set", "cannot be empty": the missing-required-config error family, from Vertex AI project/location to WeChat keys — this error's family across 18 libraries.

Related errors


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