Skip to content

fix(core): break filesystem search import cycle - #50439

Merged
rekram1-node merged 1 commit into
devfrom
filesystem-search-cycle
Sep 21, 2026
Merged

rekram1-node merged 1 commit into
devfrom
filesystem-search-cycle

Conversation

@rekram1-node

Copy link
Copy Markdown
Collaborator

Issue for this PR

Closes #49685
Closes #48372
Closes #48811
Closes #49158
Closes #48645
Closes #48803

Supersedes #49683 and the search.ts change in #48397. Unblocks #48818.

Type of change

  • Bug fix

What does this PR do?

Every prompt in a compiled build can fail with:

TypeError: undefined is not an object (evaluating 'a.name')
    at resolve (layer-node.ts)
    at SystemPrompt.environment
    at SessionPrompt.run

a.name is the minified node.name in packages/core/src/effect/layer-node.ts, walking a deps array that contains undefined.

Cause. packages/core/src/filesystem/search.ts imported the FileSystem namespace from ../filesystem only to call FileSystem.Entry.make / FileSystem.Match.make. Those two are re-exports of @opencode-ai/schema/filesystem. Meanwhile filesystem.ts imports FileSystemSearch from ./filesystem/search and lists FileSystemSearch.node in its deps. That is a runtime import cycle:

filesystem.ts ──▶ filesystem/search.ts
      ▲                    │
      └────────────────────┘

From source, evaluation order happens to work. With splitting: true in script/build.ts the bundler chooses chunk order, and when filesystem.ts evaluates first, FileSystemSearch.node is still undefined when the deps array is built. Any unrelated code change can reshuffle chunks and flip this on or off, which is why 1.18.30 broke, 1.18.31 "fixed" it without touching any of these files (git log v1.18.30..v1.18.31 has no changes to filesystem*, layer-node.ts, or the build script), Homebrew patched it by disabling splitting, and the snap is still broken.

Fix. search.ts takes Entry and Match from @opencode-ai/schema/filesystem directly and makes the remaining ../filesystem import type-only, which is erased at compile time. No runtime edge points back at filesystem.ts. Same objects, no behaviour change.

This is how the neighbouring module already does it: packages/core/src/ripgrep.ts has import { Entry, Match } from "@opencode-ai/schema/filesystem". search.ts was the outlier, and the change follows the Schema → Core dependency direction from AGENTS.md.

Credit

The commit is cherry-picked from @joe-ieta's #49683 (they remain the git author). @kernel-oops found the root cause first in #48372 / #48397 and is co-author. #48397 also adds a Python compiled-prompt harness and a CI workflow; this PR deliberately carries only the one-file fix so it can land now. #48818 (@vidit19sharma) adds a layer-node guard that turns this class of bug into a named error at startup; it should land after this.

Verification

Reproduced on current dev, not just the release. Built the single native binary (script/build.ts --single) twice on macOS arm64, once from dev and once with this change, then ran each with serve in an isolated HOME/XDG_* against a local mock OpenAI-compatible provider and sent one prompt:

binary result
dev Unexpected server error, assistant message empty. Server log: TypeError: undefined is not an object (evaluating 'a.name') at resolve (chunk-…) … at SystemPrompt.environment … at SessionPrompt.run
this branch assistant text PONG, no error

So the tip of dev currently ships this crash in compiled builds; the next release would regress without this.

Static check. A cycle scan over packages/core/src using Bun.Transpiler.scanImports (which drops import type like the bundler does):

  • dev: filesystem.ts -> filesystem/search.ts -> filesystem.ts
  • this branch: gone. The only remaining edge through filesystem.ts is its own export * as FileSystem from "./filesystem" self-reexport, which every core module has by design.

The scan also finds cycles in the plugin/internal.ts registry pattern. Those are a different shape (no deps array built from a half-initialised module) and are out of scope here; #48818's guard is the right tool for catching any that do bite.

Tests. bun typecheck in packages/core passes. packages/core: test/filesystem, location-filesystem, ripgrep, tool-read-filesystem all pass. packages/opencode: tool/glob, tool/grep pass.

Checklist

  • I have read the CONTRIBUTING.md
  • Typecheck and existing tests pass
  • Verified against compiled binaries built from dev and from this branch

search.ts imported the FileSystem namespace from ../filesystem to reach
Entry.make / Match.make, which filesystem.ts only re-exports from
@opencode-ai/schema/filesystem. That is a runtime cycle with filesystem.ts,
which imports FileSystemSearch back. With code splitting the bundler can
evaluate filesystem.ts first, leaving FileSystemSearch.node undefined in its
deps array, so the first prompt dies in SystemPrompt.environment with
TypeError: undefined is not an object (evaluating 'a.name').

Import the schema constructors directly and make the remaining FileSystem
import type-only so no runtime edge points back at filesystem.ts.

Co-authored-by: kernel-oops <300539221+kernel-oops@users.noreply.github.com>
@rekram1-node
rekram1-node merged commit f5ce4f8 into dev Sep 21, 2026
10 checks passed
@rekram1-node
rekram1-node deleted the filesystem-search-cycle branch September 21, 2026 21:41
joe-ieta added a commit to joe-ieta/opencode that referenced this pull request Sep 22, 2026
Upstream merged our filesystem search import cycle fix via anomalyco#50439: drop the local patch, update KG upstream/architecture/history, and refresh doc version baselines to 1.18.32.
difro added a commit to difro/dotfiles that referenced this pull request Sep 23, 2026
nixpkgs now builds opencode with `splitting: false` to work around the
Bun 1.4 code splitting regression (NixOS/nixpkgs#564101), so opencode
1.18.31 built with bun 1.4.2 no longer fails every prompt in
SystemPrompt.environment. Upstream also broke the filesystem import
cycle in 1.18.32 (anomalyco/opencode#50439).

Drop the nixpkgs-bun input and build opencode with the default bun
again. The glibc 2.40 interpreter patch is a separate issue and stays.
rldona pushed a commit to rldona/FlupCode that referenced this pull request Sep 24, 2026
Co-authored-by: frank <48937772+joe-ieta@users.noreply.github.com>
Co-authored-by: kernel-oops <300539221+kernel-oops@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment