different-ai/openwork · critical · ApiError

error.code

error.code

Error message

Environment variable store is invalid. Fix or remove the local env file before editing.

What it means

rethrowEnvStoreReadError is a helper that converts EnvStoreReadError — thrown when the server fails to parse the local env variable store file — into a 409 ApiError that carries the store-specific code (error.code) as the ApiError code. It tells the client the env store is corrupt/unreadable and must be repaired before any env read or write can succeed. The original error is rethrown unchanged if it is not an EnvStoreReadError.

Source

Thrown at apps/server/src/routes/core.ts:361

      throw new ApiError(400, "invalid_scope", "Token scope must be owner, collaborator, or viewer");
    }
    const label = typeof body.label === "string" ? body.label.trim() : undefined;
    const issued = await tokens.create(scope, { label });
    return jsonResponse(issued, 201);
  });

  addRoute(routes, "DELETE", "/tokens/:id", "host", async (ctx) => {
    ensureWritable(config);
    const ok = await tokens.revoke(ctx.params.id);
    if (!ok) {
      throw new ApiError(404, "token_not_found", "Token not found");
    }
    return jsonResponse({ ok: true });
  });

  function rethrowEnvStoreReadError(error: unknown): never {
    if (error instanceof EnvStoreReadError) {
      throw new ApiError(
        409,
        error.code,
        "Environment variable store is invalid. Fix or remove the local env file before editing.",
      );
    }
    throw error;
  }

  // User-level env vars (see apps/app/pr/environment-variables.md). All routes
  // require the desktop host token (not owner bearer tokens). List callers can
  // request metadata-only results so renderer settings panes do not receive
  // every raw secret value up front. Reload semantics are driven from the UI
  // after a write; this surface is user-scoped, not workspace-scoped, so no audit.
  addRoute(routes, "GET", "/env", "host-token", async (ctx) => {
    const includeValues = parseOptionalBoolean(ctx.url.searchParams.get("includeValues"), "includeValues") ?? true;
    const items = await env.list().catch(rethrowEnvStoreReadError);
    return jsonResponse({
      items: items.map((item) => ({

View on GitHub (pinned to 2b7df46e8a)

Solutions

  1. Open the local env file, fix or remove the invalid content (as the message says)
  2. Back up the file, delete it, and re-enter the variables through the API/UI
  3. Check disk permissions on the env store file
  4. Verify the file was not written by an older incompatible version

Example fix

// before (corrupt env file)
FOO=bar
BAR (missing value/quotes -> parse error)
// after
FOO=bar
BAR=baz
Defensive patterns

Strategy: try-catch

Validate before calling

import { readFileSync } from "node:fs";
try { readFileSync(envFilePath, "utf8"); } catch { console.error("env store unreadable — fix before calling /env APIs"); }

Type guard

function isEnvStoreReadError(e: unknown): e is { status: 409; code: string; message: string } {
  return typeof e === "object" && e !== null && (e as { status?: number }).status === 409;
}

Try / catch

try {
  await api.get("/env");
} catch (e) {
  if (isEnvStoreReadError(e)) {
    console.error(`Env store invalid (code=${e.code}); fix or remove the local env file before editing.`);
    return;
  }
  throw e;
}

Prevention

When it happens

Trigger: Any /env route (list, get, set, delete) calling env.list().catch(rethrowEnvStoreReadError) when the local env file is malformed, has invalid syntax, wrong permissions, or an unsupported format.

Common situations: A user hand-edited the env file and introduced a syntax error; a partial write/crash left the file truncated; the file was created by a different app version with an incompatible format.

Related errors


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