GitHub Copilot `file_search` and `grep_search` support an undocumented workspace-folder-name scope prefix, and reject a wrong one silently
- Dominant language
- TypeScript
- Stars
- 193k
- Forks
- 42.4k
- PR merge metrics
- PR metrics pending
Description
This is a bug that is constantly tripping up models in multi-root workspaces. The models search for something and then can't find it. This along with things like #328075 and the other issues mentioned mean that a large percentage of the time, models think files don't exist! You can imagine how this reduces efficiency (and burns credits). As mentioned in #328287, I would appreciate your giving these priority; this has cost me a significant amount of time and money to investigate both issue, and most users probably don't even know that this is constantly producing bad search result problems behind the scenes.
Ticket below drafted by Claude Opus 5:
## Summary
Both `file_search` and `grep_search` accept a workspace folder's **name** as a leading path segment to scope a search to one root in a multi-root workspace. The capability works correctly, including for names containing spaces. The problem is that a caller cannot obtain the value it requires, and cannot detect having got it wrong:
- **Not discoverable.** Neither tool's description mentions the form. Both document only absolute-path scoping. And a folder's name is not derivable from anything else a caller holds — it defaults to the directory name but is replaced whenever the workspace file supplies one.
- **Not diagnosable.** A leading segment matching no workspace folder returns an empty result, indistinguishable from a legitimate no-match.
A caller therefore falls into a predictable trap: it holds each folder's absolute path — every tool result contains one — derives the directory name, uses that as the prefix, and receives zero results with nothing indicating the pattern could never have matched.
This is a discoverability and diagnostics issue rather than a behavioral defect. Given the right input the tools do the right thing. The right input is simply not obtainable from what they expose.
## Environment
- OS: Windows 11
- VS Code: 1.131.0
- Workspace: Multi-root, two folders, each given a `name` in the workspace file that differs from its directory name
The issue concerns name resolution rather than path handling, so it should be platform-independent.
All reproduction below was performed with **no editors open**, to isolate it from #328287, which otherwise contaminates `grep_search` results.
## Setup
```
C:\projects\alpha-svc\
notes.md
C:\projects\beta-svc\
other.md
```
`example.code-workspace`:
```json
{
"folders": [
{ "path": "C:/projects/alpha-svc", "name": "Alpha Service" },
{ "path": "C:/projects/beta-svc", "name": "Beta Service" }
]
}
```
## Results
`file_search`, `query`:
| Pattern | Result |
|---|---|
| `**/notes.md` | ✅ searches both roots |
| `Alpha Service/**/notes.md` | ✅ scoped — **undocumented form** |
| `Alpha Service/notes.md` | ✅ exact match; spaces need no quoting |
| `C:/projects/alpha-svc/**/notes.md` | ✅ scoped — documented form |
| `C:/projects/alpha-svc` | ✅ everything in that root — documented form |
| `alpha-svc/**/notes.md` | ❌ empty, no diagnostic |
`grep_search`, `includePattern`:
| Pattern | Result |
|---|---|
| `**/*.md` | ✅ searches both roots |
| `Alpha Service/**` | ✅ scoped — **undocumented form** |
| `C:/projects/alpha-svc` | ✅ scoped — documented form |
| `C:/projects/alpha-svc/**` | ✅ scoped — documented form |
| `alpha-svc/**` | ❌ empty, no diagnostic |
The two tools agree on every row. The only failing one in each is the row a caller is most likely to construct.
## Where a caller could learn the name, and why neither place works
There are exactly two.
**1. The tool descriptions — silent on names entirely.**
`file_search`, description:
> In a multi-root workspace, you can scope the search to a specific workspace folder by using the absolute path to the folder as the query, e.g. `/path/to/folder/**/*.ts`.
`file_search`, parameter `query`:
> Search for files with names or paths matching this glob pattern. Can also be an absolute path to a workspace folder to scope the search in a multi-root workspace.
`grep_search`, description:
> In a multi-root workspace, you can scope the search to a specific workspace folder by using the absolute path to the folder as the includePattern.
`grep_search`, parameter `includePattern`:
> Search files matching this glob pattern. Will be applied to the relative path of files within the workspace. To search recursively inside a folder, use a proper glob pattern like `"src/folder/**"`. Do not use `|` in includePattern. Can also be an absolute path to a workspace folder to scope the search in a multi-root workspace.
Absolute-path scoping appears in four places. Name-prefix scoping appears in none, despite working in both tools. `file_search`'s description also says *"Glob patterns match from the root of the workspace folder"* — singular, which is ambiguous in a multi-root workspace and gives no hint that a leading segment selects among folders.
**2. The workspace context given to the model — contains the names, but does not identify them.**
That context presents the two facts separately and in different forms:
```
I am working in a workspace with the following folders:
- C:\projects\alpha-svc
- C:\projects\beta-svc
I am working in a workspace that has the following structure:
Alpha Service/
notes.md
Beta Service/
other.md
```
The **paths** are an explicit, labelled list. The **names** appear only as top-level labels of a rendered directory tree, unlabelled as names, with nothing stating that they are what a scope prefix takes or that they may diverge from the paths listed directly above.
The result is heavily asymmetric exposure. A model sees the path form constantly — in that list, in every prior tool result, in terminal output — and the name form only incidentally, in a structure that reads as a picture of the file layout. Deriving the prefix from the path is the natural inference, and it fails silently.
## Why a wrong value is undetectable
An unresolvable leading segment produces the same output as a well-formed query with no matches: nothing. #293428's original misleading message — which falsely blamed `.gitignore`/`search.exclude` — was replaced with an empty result. That removed the misinformation but supplied nothing in its place, so a malformed pattern and an honest no-match are now identical from the caller's side.
It is not always even empty. With any editor open, #328287 causes matching open documents to be returned regardless of `includePattern`, so a wrong prefix may yield a small, plausible, **non-empty** result set. That is strictly worse than empty, and it is what obscured this issue during investigation: the failure looked like a partially-working scope rather than a rejected one.
## Impact
An empty result reads as evidence of absence. An agent concluding that a symbol has no references, or that a file does not exist, acts on that conclusion — an incomplete refactor, a missed dependency update, a file recreated from scratch because a search said it was not there.
The failure also appears nondeterministic from the outside. In a workspace whose folders carry no explicit names, the directory name *is* the folder name, so the prefix works. In a workspace where an author named the folders for readability, the identical construction silently fails. The same agent behavior therefore succeeds in one project and fails in another, for a reason nothing in the tool surface explains.
## Recommendation
**Make the value obtainable.**
1. **Pair each folder's name with its path in the workspace context.** *(Different component — prompt assembly rather than the search tools.)* For example:
```
Workspace folders:
"Alpha Service" → C:\projects\alpha-svc
"Beta Service" → C:\projects\beta-svc
```
This is the only remedy that does not require the caller to have read a tool description, which makes it the most reliable for a model that learned the name-prefix form second-hand — as this one did.
2. **Document the name-prefix form** in both tool descriptions, alongside the existing absolute-path sentence, and state that a folder's name comes from the workspace configuration and may differ from its directory name.
**Make a wrong value detectable.**
3. **Report a pattern that cannot match**, rather than returning empty. For an unresolved leading segment, naming the alternatives also closes the discoverability gap directly:
```
No workspace folder named "alpha-svc". Folders in this workspace: "Alpha Service", "Beta Service".
```
The same principle extends to any pattern incapable of matching a file — for instance a bare directory path below a workspace root, which `includePattern` also accepts and silently resolves to nothing.
4. **Detect the specific near-miss.** When a leading segment matches a folder's directory name but not its configured name, say so. That is the exact mistake described here and is cheaply detectable.
5. **Consider accepting the directory name as an alias** where unambiguous across folders. Optional; with item 3 in place a wrong prefix becomes self-correcting anyway.
Items 1 and 3 carry most of the value and are complementary: item 1 prevents the wrong prefix from being formed, item 3 catches it whenever one is formed regardless of cause. Items 2, 4, and 5 help a caller who is already reading the documentation.
## Related issues
- #328287 — `grep_search` returns files outside `includePattern` when they are open in an editor. Interacts with this issue as described above.
- #293428 — `grep_search` `includePattern` silently failed for any workspace-folder-name prefix (fixed in 1.112.0). That fix established the capability this issue asks to have made discoverable.
- #328102 — remaining backslash-boundary defect in the same prefix-resolution path.
- #293430 — `\**\` globs silently degrade to single-segment wildcards.
- #328075 — truncation is not reported explicitly enough, producing false "file does not exist" conclusions.
Contributor guide
Assessment
This issue has not been assessed yet.