Why Gemini CLI can't read a gitignored file
In Gemini CLI, the .gitignore file you already keep for Git does double duty: the CLI reads the same patterns as a visibility rule for its own file tools. A file can sit in your working tree, open fine with cat, and still be refused by read_file. The refusal is a context filter, not a file permission.
Run gemini --version first. This page describes v0.65.0, the stable release on 20 October 2026.
Checked against Gemini CLI's documentation on 27 October 2026.
Status, 27 October 2026: the docs describe .gitignore and .geminiignore separately but do not spell out which wins. The v0.65.0 source merges them into one matcher, with .geminiignore applied after .gitignore, so a ! rule can re-include a file unless a parent directory is ignored. A report on v0.30.0 said the negation did not work (#20586, closed 7 June 2026 after a request to retest on a current version). Test the current build before assuming it is still broken. Unpaid-tier and Google One users were moved to Antigravity CLI on 18 June 2026, so this page applies to paid, API-key, Vertex AI and enterprise installs; the Gemini CLI hub has the details.
The error#
read_file checks the path before reading. When a rule matches, the tool returns:
File path '/path/to/file' is ignored by configured ignore patterns."Configured ignore patterns" means .gitignore, .geminiignore, and any extra ignore files in context.fileFiltering.customIgnoreFilePaths. The check is in the read_file tool, and the same file filter is used by search and by the @ path reader.
@file is the quiet case. The path reader filters the file out and returns nothing. The CLI shows a short notice in the UI that the file was ignored and not included in the prompt, but the model gets no content. If that notice scrolls past, the model can say the file is empty or missing after you included it with @. Search tools can also skip it without saying why if you only look at the results.
Two lists, both on by default#
| Setting | Default | What it does |
|---|---|---|
context.fileFiltering.respectGitIgnore | true | Applies .gitignore rules in a normal repository, including nested .gitignore files and .git/info/exclude, to the file tools and search. |
context.fileFiltering.respectGeminiIgnore | true | Applies .geminiignore. |
context.fileFiltering.customIgnoreFilePaths | [] | Adds ignore files that take precedence over both. |
In a linked worktree .git is a file, so this particular exclude file is not read; the worktree's real git directory holds it.
Both files use gitignore syntax: blank lines and # comments, globs, a trailing / for directories, a leading / to anchor, and ! to negate. .geminiignore belongs at the directory where you start Gemini CLI — normally the repository root — and edits require a restart.
The source builds one matcher: Git patterns first, then .geminiignore, then custom ignore files. Later patterns win, which is why a .geminiignore negation can override a .gitignore rule in the current build.
When a negation in `.geminiignore` still does nothing#
In the current build a .geminiignore negation normally does override a .gitignore rule; the cases below are the ones where it cannot.
- A parent directory is ignored. Git's own rule says you cannot re-include a file when a directory above it is excluded. If
.gitignorehassecrets/and you add!secrets/key.md, the file stays hidden. Unignore the directory, or move the file out of it. The Git documentation states the rule. - You started in a subdirectory. The ignore files are read from the workspace root, not from parents above it. Run
pwd; start at the repository root, or put the rule in the ignore file at the root you actually use. - A custom ignore file matches it.
customIgnoreFilePathsis applied after both standard files. Read those files too. - The change did not take effect.
.geminiignoreedits need a restart. Settings edits also need a restart, and a project settings file can differ from your global one. Check/settingsand the file in the scope you edited. - The path is a symlink that resolves outside the project. The file filter treats that as ignored even when both settings are off. Run
realpathon the file. - The message is different. "Path not in workspace" or "File not found" is not the ignore filter. The fix here will not help.
Fix one file: add a negation#
If the file is the exception and the directory around it is not ignored, add a negation to .geminiignore:
# .geminiignore
!config/local.example.jsonRestart Gemini CLI, then ask it to read the file. Watch the read_file result in the transcript: if the error is gone and the tool returns the content, the rule worked. The model's summary is not the check; the tool result is.
If the file is inside an ignored directory, the negation cannot bring it back. Unignore the directory and re-ignore its other contents, or move the file. This is Git's rule, not a Gemini CLI quirk.
Fix many files: stop applying `.gitignore`#
When the repository has a whole class of files the agent should see, turn off the Git layer for the file tools. Run /settings, find "Respect.gitignore", set it to false, and restart. The same change in a settings file:
{
"context": {
"fileFiltering": {
"respectGitIgnore": false
}
}
}Put it in ~/.gemini/settings.json for every project, or .gemini/settings.json for one. The setting is listed in the settings reference.
Then move the exclusions you still want into .geminiignore: node_modules/, dist/, build output, .env, and anything with credentials. Turning off the Git layer without that makes search slower and can put secrets in the model's context. .geminiignore still applies when respectGitIgnore is false; that is what keeps the two jobs separate.
A third file for per-machine exceptions#
customIgnoreFilePaths adds ignore files that are applied after both standard files. A local file such as .geminiignore.local can carry personal exceptions without changing the repository's .geminiignore:
{
"context": {
"fileFiltering": {
"customIgnoreFilePaths": [".geminiignore.local"]
}
}
}It uses the same syntax, and because it is applied last, a ! rule there wins over .geminiignore as well — again, except inside an ignored directory. Keep the file out of Git if it is personal.
Check which rule matched#
git check-ignore shows the .gitignore file and line that matches:
git check-ignore -v path/to/fileIf the file is tracked, add --no-index, because ordinary git check-ignore says nothing for tracked files:
git check-ignore --no-index -v path/to/fileGemini CLI's matcher applies .gitignore patterns whether or not Git tracks the file. A tracked file can still be hidden from the agent by a pattern in .gitignore.
git check-ignore consults the repository's ignore files; Gemini's matcher starts at the workspace root. If you started in a subdirectory, a rule that Git prints from the repository root may not be the rule Gemini used. Run git check-ignore from the directory where you launched Gemini, and read the .gitignore and .geminiignore files under that root; a .gitignore above it is not loaded by Gemini. If you launch at the repository root, run the check there.
If both commands print nothing, Git is not the source. Read .geminiignore, the files in customIgnoreFilePaths, and realpath for a symlink. There is no /memory-style command that prints the effective ignore list, so the files and the tool result are the evidence.
The shell can still read it#
read_file refuses the file, but run_shell_command does not apply the ignore filters. cat.env can succeed while the file tool refuses the same path. A report on v0.33.1 described the agent reading and editing a .env that was in .gitignore (#22881, closed 27 April 2026; the reply pointed to .geminiignore). That is the design: these files are context filters, not access controls.
If a file must stay out of the agent's reach, do not rely on .gitignore or .geminiignore alone. Use the sandbox (OS-level isolation for tool calls) and permission rules (allow, ask, or deny per tool); folder trust — the switch that decides whether a project's own settings and hooks are trusted — is a third layer. The permissions guide covers those layers. For secrets, the agent memory secrets guide covers what should never be captured in the first place.
Where to go next#
- What /memory shows in Gemini CLI — the other place files enter the prompt.
- Does Gemini CLI read AGENTS.md? — what loads, in what order.
- Why Gemini CLI keeps asking for permission — the boundary that does stop tool calls.
- Gemini CLI guides — the rest of the set.