Skip to content

[Bug]: A file link with ../ to a file outside the workspace fails to open #16354

Closed

Description

@genericrohan

Before submitting

  • I searched existing issues and did not find a duplicate.
  • I included enough detail to reproduce or investigate the problem.

Area

apps/web

Steps to reproduce

  1. Open a thread whose workspace is /home/me/project.
  2. Create a file in a sibling folder, for example /home/me/other/notes.md.
  3. Have the agent mention it with a parent-folder path, as a markdown link [notes.md](../other/notes.md) or as inline code ../other/notes.md.
  4. Click the chip.

Expected behavior

The file opens read-only in the file viewer, the same as it does when the agent writes /home/me/other/notes.md or ~/other/notes.md.

Actual behavior

The file viewer shows:

Failed to read workspace file '../other/notes.md' in '/home/me/project'.

The chip tooltip shows /home/me/project/../other/notes.md. The absolute form and the ~/ form of the same file open correctly in the same message.

Impact

Minor bug or occasional failure

Version or commit

main @ 68e50db

Environment

Windows desktop app with the server in WSL2, Ubuntu 24.04. The cause is in shared web code, so I do not think it is specific to WSL.

Cause

resolvePathLinkTarget in apps/web/src/terminal-links.ts joins the path to the workspace root and keeps the .. segment. The result, /home/me/project/../other/notes.md, still starts with the workspace root. workspaceRelativeFilePath compares by string prefix, so it classifies the file as a workspace file with the relative path ../other/notes.md. The server refuses a relative path that leaves the workspace. An absolute path would have been read as a host file.

Mobile already guards against this. resolveWorkspaceRelativeFilePath in apps/mobile/src/features/files/filePath.ts has the comment "/repo/../x starts with the root but escapes it".

Related issues

Proposed fix

Collapse . and .. segments in resolvePathLinkTarget before the workspace check. A file outside the workspace then opens read-only as a host file. A ../ link that stays inside the workspace, such as a link between two docs folders, still opens as a workspace file.

I have this fix with focused tests in terminal-links.test.ts and markdown-links.test.ts. I can open a PR if the direction is right.

Workaround

Ask the agent to write the absolute path.

Investigated with Claude Code, Opus 5.5.

Activity

  1. juliusmarminge commented on Oct 6, 2026

    @juliusmarminge
    Member

    Note

    Grok responding on behalf of Julius.

    Triage

    Thanks again for another precise report, @genericrohan! This matches what we see in the web file-link resolver. It's separate from #8251 (a relative path without .. resolved against a project root that isn't the agent's working directory) and #15215 (links to folders outside the workspace).

    What I found

    • resolvePathLinkTarget in apps/web/src/terminal-links.ts joins a relative link onto the workspace root and leaves . and .. in the string. For [notes.md](../other/notes.md) with root /home/me/project, the chip target becomes /home/me/project/../other/notes.md, which is also what the tooltip shows.
    • workspaceRelativeFilePath only checks that the string starts with the root, so it treats this as the workspace-relative path ../other/notes.md. The server's resolveRelativePathWithinRoot rejects that, and the viewer shows Failed to read workspace file '../other/notes.md' in '/home/me/project'.
    • Absolute and ~/ paths never get the root prefix, so they open read-only as host files. An absolute link that still contains .. (e.g. /home/me/project/../other/notes.md) fails the same way, since it's returned unchanged and still starts with the root.
    • The Windows desktop app and WSL2 aren't part of the cause.

    Likely fix area

    Your proposal of collapsing . and .. before the workspace check fits the code. A few details that may matter there:

    • Keep the collapse lexical (no realpath) and apply it to the path only, preserving any :line / :column suffix, and expanding ~/ before collapsing.
    • An in-workspace link like docs/guide/../readme.md should stay a workspace file. The mobile check in apps/mobile/src/features/files/filePath.ts treats every .. after the root as outside, which would misclassify that case.
    • On Windows, avoid climbing above the drive root, or above the share on UNC paths.
    • The server's rejection of relative paths that escape the root can stay as is.
    • terminal-links.test.ts and markdown-links.test.ts are natural places to cover the outside-workspace case, an in-workspace .. link, and a line suffix.

    A maintainer will decide on the fix direction.

  2. added
    bugSomething is broken or behaving incorrectly.
    via-triageFiled through npx t3 triage
    on Oct 6, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething is broken or behaving incorrectly.via-triageFiled through npx t3 triage

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions