Skip to content

Docs: outside Git repos, config lookup walks up to the filesystem root — stray ancestor opencode.json (e.g. ~/opencode.json) silently overrides global config (401) #58055

Closed as not planned

Description

@yanghonggang

Description

Outside a Git repository, OpenCode walks up from the cwd all the way to the filesystem root (/) and merges every opencode.json / opencode.jsonc it finds — so a forgotten ~/opencode.json silently overrides the global config for every non-Git directory below it (in my case it swapped provider credentials → misleading 401 Unauthorized with a valid key), while the docs claim the walk only "traverses up to the nearest Git directory".
Repro (installs latest opencode into a throwaway sandbox; nothing touches your real config; verified on 1.19.3 = current @latest, and 1.14.48):

#!/usr/bin/env bash
set -uo pipefail
TMP=$(mktemp -d); trap 'rm -rf "$TMP"' EXIT
if [ -n "${OPENCODE_BIN:-}" ]; then
  OPENCODE="$OPENCODE_BIN"
else
  echo ">> installing opencode-ai@${OPENCODE_VERSION:-latest} into sandbox ..."
  npm install --silent --prefix "$TMP/pkg" "opencode-ai@${OPENCODE_VERSION:-latest}" \
    || { echo "npm install failed (npm + network required; or use OPENCODE_BIN)"; exit 1; }
  OPENCODE="$TMP/pkg/node_modules/.bin/opencode"
fi
"$OPENCODE" --version
# Isolate ALL state so the tested binary cannot read/migrate the real global config.
export XDG_CONFIG_HOME="$TMP/xdg/config" XDG_DATA_HOME="$TMP/xdg/data" XDG_CACHE_HOME="$TMP/xdg/cache"
export OPENCODE_DISABLE_AUTOUPDATE=1 OPENCODE_DISABLE_MODELS_FETCH=1
mkdir -p "$TMP/tree/sub"
printf '%s\n' '{ "provider": { "openai": { "options": { "apiKey": "sk-global-correct", "baseURL": "https://global-correct.invalid/v1" } } } }' > "$TMP/global.json"
printf '%s\n' '{ "provider": { "openai": { "options": { "apiKey": "sk-ancestor-wrong", "baseURL": "https://ancestor-wrong.invalid/v1" } } } }' > "$TMP/tree/opencode.json"
cd "$TMP/tree/sub"
export OPENCODE_CONFIG="$TMP/global.json"   # acts as the "global config" layer (loaded below project configs)
winner() { "$OPENCODE" debug config 2>/dev/null | grep -oE '(ancestor-wrong|global-correct)' | head -1 || true; }
echo "case 1 (cwd NOT in a Git repo): $(winner)"
git init -q .
echo "case 2 (cwd inside a Git repo): $(winner)"

outputs:

[hehe@localhost test]$ OPENCODE_VERSION=1.19.3 bash opencode-config-traversal-repro.sh 
>> installing [email protected] into sandbox ...
(node:104225) [DEP0060] DeprecationWarning: The `util._extend` API is deprecated. Please use Object.assign() instead.
(Use `node --trace-deprecation ...` to show where the warning was created)
[..................] / rollbackFailedOptional: verb npm-session 2f97cd0790509e9a
[..................] / rollbackFailedOptional: verb npm-session 2f97cd0790509e9a
(node:104225) [DEP0176] DeprecationWarning: fs.F_OK is deprecated, use fs.constants.F_OK instead
+ [email protected]
added 5 packages in 43.019s
1.19.3
case 1 (cwd NOT in a Git repo): ancestor-wrong
case 2 (cwd inside a Git repo): global-correct

ancestor-wrong = ancestor-directory opencode.json overrode the global config (BUG)
global-correct = ancestor config was ignored (behavior the docs describe)
[hehe@localhost test]$ 
[hehe@localhost test]$ 
[hehe@localhost test]$ OPENCODE_BIN=$(which opencode) bash opencode-config-traversal-repro.sh 
1.14.48
case 1 (cwd NOT in a Git repo): ancestor-wrong
case 2 (cwd inside a Git repo): global-correct

ancestor-wrong = ancestor-directory opencode.json overrode the global config (BUG)
global-correct = ancestor config was ignored (behavior the docs describe)

(The marker is baseURL because newer versions redact apiKey to "***" in debug config; the override mechanism is the same.)
Workaround: OPENCODE_DISABLE_PROJECT_CONFIG=1, or audit ancestor directories (especially $HOME) for stray opencode.json.

Plugins

No response

OpenCode version

1.19.3 & 1.14.48

Steps to reproduce

No response

Screenshot

No response

Operating System

CentOS Linux release 8.4.2105

Terminal

No response

Activity

  1. opencode-agent commented on Oct 22, 2026

    @opencode-agent
    Contributor

    Thanks for the detailed report and the self-contained repro script!

    You're running OpenCode v1 (1.19.3 and 1.14.48). v1 now only gets fixes for critical bugs (data loss, security problems, or crashes or breakage with no workaround), so this is unlikely to be fixed there. You've already found the workarounds: OPENCODE_DISABLE_PROJECT_CONFIG=1, or removing the stray ancestor opencode.json.

    We encourage upgrading to v2 (npm package @opencode/cli, opencode command). In v2, walking up through every ancestor directory is intentional, and it happens inside Git repos too, not only outside them. The v2 docs were updated to say so (#45681). In v2 the global config directory is not picked up again by that walk, but an opencode.json placed directly in an ancestor such as ~ still applies as project config. A stray ~/opencode.json should therefore be removed, or moved into the global config directory if that's what you meant it to be.

    Related:

    If you think this is critical, or you see unexpected behaviour on v2, please reply here with the details.

  2. opencode-agent commented on Oct 23, 2026

    @opencode-agent
    Contributor

    Closing this as not planned. It was reported on OpenCode v1 (1.19.3 / 1.14.48), which only gets critical fixes, and you have workarounds: OPENCODE_DISABLE_PROJECT_CONFIG=1, or removing the stray ancestor opencode.json. We waited a day to hear whether this is critical for you or also happens on v2, and there was no reply.

    In v2, project config discovery walks every ancestor directory up to the filesystem root, inside and outside Git repos, and the v2 docs say so (#45681). If you see unexpected config behaviour on v2, please open a new issue with the version and the steps to reproduce. Thanks again for the detailed repro script!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions