Symlinked directories not visible in project picker (opencode serve) #7425

Open
opened 2026-02-16 18:07:08 -05:00 by yindo · 3 comments
Owner

Originally created by @frizikk on GitHub (Jan 24, 2026).

Originally assigned to: @rekram1-node on GitHub.

Description

Description

Symlinked directories are not visible in the project picker when running opencode serve.

Steps to Reproduce

  1. Create a symlink to a directory:
    ln -s /mnt/data/Projects ~/Projects
    
  2. Run opencode serve
  3. Open web UI and use project picker
  4. Navigate to ~/Projects
    Expected: Symlinked subdirectories appear as directories
    Actual: They are hidden or shown as files

Root Cause

fs.readdir() with withFileTypes: true returns entry.isDirectory() = false for symlinks, even when pointing to directories.
Affected code in packages/opencode/src/file/index.ts:

  • File.list() - directory listing API
  • Home directory scanning

Environment

  • OS: Linux
  • OpenCode: latest

Plugins

No response

OpenCode version

1.1.34

Steps to reproduce

  1. Create a symlink to a projects directory:
    ln -s /mnt/data/Projects ~/Projects
    
  2. Start the server:
    opencode serve
    3. Open web UI in browser
  3. Open project picker dialog
  4. Navigate to ~/Projects

Screenshot and/or share link

No response

Operating System

CachyOS Linux (arch btw)

Terminal

Ghostty

Originally created by @frizikk on GitHub (Jan 24, 2026). Originally assigned to: @rekram1-node on GitHub. ### Description ## Description Symlinked directories are not visible in the project picker when running `opencode serve`. ## Steps to Reproduce 1. Create a symlink to a directory: ```bash ln -s /mnt/data/Projects ~/Projects ``` 2. Run `opencode serve` 3. Open web UI and use project picker 4. Navigate to `~/Projects` **Expected:** Symlinked subdirectories appear as directories **Actual:** They are hidden or shown as files ## Root Cause `fs.readdir()` with `withFileTypes: true` returns `entry.isDirectory() = false` for symlinks, even when pointing to directories. Affected code in `packages/opencode/src/file/index.ts`: - `File.list()` - directory listing API - Home directory scanning ## Environment - OS: Linux - OpenCode: latest ### Plugins _No response_ ### OpenCode version 1.1.34 ### Steps to reproduce 1. Create a symlink to a projects directory: ```bash ln -s /mnt/data/Projects ~/Projects 2. Start the server: opencode serve 3. Open web UI in browser 4. Open project picker dialog 5. Navigate to ~/Projects ### Screenshot and/or share link _No response_ ### Operating System CachyOS Linux (arch btw) ### Terminal Ghostty
yindo added the bugweb labels 2026-02-16 18:07:08 -05:00
Author
Owner

@github-actions[bot] commented on GitHub (Jan 24, 2026):

This issue might be a duplicate of existing issues. Please check:

  • #8313: Path traversal vulnerability via symlinks and cross-drive paths - related to symlink handling in src/file/index.ts
  • #7498: Grep Tool Fails on Symlinks - similar symlink visibility and handling issues in the filesystem API
  • #8307: ripgrep causes Grep tool to fail in the presence of broken symlinks - also related to symlink handling
  • #8616: Grep tool returns only error messages if directory has invalid symlinks - symlink-related directory traversal issues
  • #7597: Web frontend "open project" on Windows only lists user folder and fails for absolute/relative paths - related project picker visibility issue in web mode

Feel free to ignore if none of these address your specific case.

@github-actions[bot] commented on GitHub (Jan 24, 2026): This issue might be a duplicate of existing issues. Please check: - #8313: Path traversal vulnerability via symlinks and cross-drive paths - related to symlink handling in `src/file/index.ts` - #7498: Grep Tool Fails on Symlinks - similar symlink visibility and handling issues in the filesystem API - #8307: ripgrep causes Grep tool to fail in the presence of broken symlinks - also related to symlink handling - #8616: Grep tool returns only error messages if directory has invalid symlinks - symlink-related directory traversal issues - #7597: Web frontend "open project" on Windows only lists user folder and fails for absolute/relative paths - related project picker visibility issue in web mode Feel free to ignore if none of these address your specific case.
Author
Owner

@jeroenev commented on GitHub (Feb 6, 2026):

They are also not visible in ripgrep (search tool) and cannot be @tagged in opencode

@jeroenev commented on GitHub (Feb 6, 2026): They are also not visible in ripgrep (search tool) and cannot be @tagged in opencode
Author
Owner

@panta82 commented on GitHub (Feb 7, 2026):

Just got hit by this. My clanker analyzed and wrote this:

This is a regression introduced in commit c0e71c426 (PR #11415 — "fix: don't --follow by default for grep and other things using ripgrep").

The change in packages/opencode/src/file/ripgrep.ts flipped the default for --follow from opt-out to opt-in:

  • if (input.follow !== false) args.push("--follow")
  • if (input.follow) args.push("--follow")

This was applied to both Ripgrep.files() and Ripgrep.search(). The intent was to stop grep from following symlinks by default, but it also broke the file indexer which never passes follow explicitly.

The file indexer at packages/opencode/src/file/index.ts:170 calls:
for await (const file of Ripgrep.files({ cwd: Instance.directory })) {

Since follow is undefined, the old code treated it as undefined !== false → true → --follow added. The new code treats it as falsy → --follow omitted.

Impact: Symlinked directories in a project are no longer traversed by the @ file picker or ripgrep search in the TUI. This affects workspace setups that use symlinks to aggregate multiple project directories.

Fix: The file indexer call should explicitly pass follow: true:
for await (const file of Ripgrep.files({ cwd: Instance.directory, follow: true })) {

@panta82 commented on GitHub (Feb 7, 2026): Just got hit by this. My clanker analyzed and wrote this: > This is a regression introduced in commit c0e71c426 (PR #11415 — "fix: don't --follow by default for grep and other things using ripgrep"). > > The change in packages/opencode/src/file/ripgrep.ts flipped the default for --follow from opt-out to opt-in: > > - if (input.follow !== false) args.push("--follow") > + if (input.follow) args.push("--follow") > > This was applied to both Ripgrep.files() and Ripgrep.search(). The intent was to stop grep from following symlinks by default, but it also broke the file indexer which never passes follow explicitly. > > The file indexer at packages/opencode/src/file/index.ts:170 calls: > for await (const file of Ripgrep.files({ cwd: Instance.directory })) { > > Since follow is undefined, the old code treated it as undefined !== false → true → --follow added. The new code treats it as falsy → --follow omitted. > > Impact: Symlinked directories in a project are no longer traversed by the @ file picker or ripgrep search in the TUI. This affects workspace setups that use symlinks to aggregate multiple project directories. > > Fix: The file indexer call should explicitly pass follow: true: > for await (const file of Ripgrep.files({ cwd: Instance.directory, follow: true })) {
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: anomalyco/opencode#7425