anomalyco / anomalyco/opencode

Desktop (Windows): EPERM reading .config/opencode/opencode.jsonc even though Node reads it fine; rename+recreate (identical bytes) fixes it

Open
#41,041 2 comments 0 reactions 1 assignee View on GitHub

@Hona is already working on this.

Since Aug 7, 2026.

Dominant language
TypeScript
Stars
209k
Forks
27.5k
PR merge metrics
PR metrics pending

Description

Problem

On Windows 11, the OpenCode Desktop app fails to start: the server returns HTTP 500 / "Unexpected server error", and the log shows EPERM while reading the global config file:

FileSystem.readFile(C:\Users\<user>\.config\opencode\opencode.jsonc)
  -> EPERM: operation not permitted, open

This happens at startup during Config.getGlobal().

What I observed

  • The file opencode.jsonc exists and contains a valid { "$schema": "https://opencode.ai/config.json" }.
  • Node reads it fine: node -e "fs.readFileSync(process.env.USERPROFILE+'/.config/opencode/opencode.jsonc')" returns the content.
  • Permissions look fine; I already fixed broken ACLs on .config and .local\share (takeown + icacls). Node, PowerShell and Explorer all read/write normally there.
  • Yet OpenCode's own read still returns EPERM. Node can read the same file, OpenCode cannot.

What I tried that fixed it

Renamed the file and let OpenCode recreate it:

Rename-Item "$env:USERPROFILE\.config\opencode\opencode.jsonc" opencode.jsonc.bak

After that OpenCode started fine and has been stable (survives restart and reboot). Notably:

  • The recreated file is byte-for-byte identical to the old one (same SHA256), so it's not about content.
  • Only the file's filesystem metadata changed. That means the old file's ACL/attributes were the problem, most likely because it was created while the container directory was still in a broken ACL state (the same state that earlier caused EPERM: mkdir).

Suspected root cause

A Windows ACL edge case on that one config file, exposed by the way the bundled runtime opens files — not a bug in config parsing. Node opens with one access mask and succeeds; OpenCode's startup read is denied. I'm reporting it mainly so startup failures like this (and the opaque HTTP 500) are easier to diagnose.

Suggested improvement (optional)

packages/core/src/global.ts does await Promise.all([... fs.mkdir(...)]) for the config/data/state dirs with no error handling, so one EPERM aborts startup and shows only a bare HTTP 500. Wrapping each mkdir with a catch + a log line naming the directory (and the takeown/icacls hint) would make this class of failure self-explanatory.

Related: #36124 (embedded-runtime-on-Windows theme, though that one is a different root cause).

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.