Summary
GitignoreParser rescopes patterns from nested .gitignore files by prefixing the containing directory's relative path, but does not escape glob metacharacters in that path. A directory whose name contains * therefore produces a pattern that matches far more than it should — in the worst case silently excluding the entire project, so indexing reports 0 files with exit code 0 and no error.
Root cause
serena/util/file_system.py, _parse_gitignore_content (v1.6.1, line 272):
adjusted_pattern = os.path.join(rel_dir, "**", line)
rel_dir is a filesystem name, but it is being interpolated into a pattern context. Lines 263 and 269 have the same issue.
Concrete case
A stray uv/venv directory named *** at the project root. Every venv ships a .gitignore whose entire content is *, so:
rel_dir = ***, line = *
- adjusted pattern =
***/**/*
In gitignore/pathspec syntax *** is just asterisks — a wildcard matching any first segment. So ***/**/* means "ignore every path at depth >= 2." All sources under src/, packages/, etc. are excluded. Root-level files like pyproject.toml survive, which is why nothing errors.
Observed: Indexing: 0it [00:00, ?it/s] / Indexed files per language: (empty), exit 0. With language auto-detection it instead reports No source files for supported language servers were found, which points the user at language configuration — the wrong place entirely.
Verified by running GitignoreParser directly against the project: it loads a spec from ***/.gitignore with adjusted pattern ***/**/*, and should_ignore() returns True for 1009 of 1009 tracked .py files.
Reproduction
mkdir -p repro/pkg && cd repro && git init -q
printf 'def f():\n pass\n' > pkg/mod.py
mkdir '***' && printf '*\n' > '***/.gitignore' # what any venv looks like
uvx --from serena-agent serena project index --language python .
# => Indexed files per language: (empty) — expected: python=1
Removing the *** directory, or setting ignore_all_files_in_gitignore: false, indexes normally.
Impact
Silent and misdiagnosing. Serena appears configured and healthy, project.yml looks correct, exit code is 0 — but every symbol tool (find_symbol, find_referencing_symbols) returns nothing because the index is empty. In our case this went unnoticed for some time and read as a language-server problem. Any directory named with glob metacharacters triggers it; stray venvs named with asterisks are the realistic path, but foo[1], a{b} and similar would also misbehave.
Suggested fix
Escape glob metacharacters in rel_dir before joining, so the directory name is matched literally. pathspec honors backslash-escaped metacharacters — \*\*\*/ matches only the literal *** directory (confirmed as a workaround). Something equivalent to escaping *?[]{} in rel_dir at all three join sites.
A cheaper mitigation, worth having regardless: warn when a loaded gitignore spec excludes 100% of candidate files, rather than reporting an empty index as success.
Workaround
ignore_all_files_in_gitignore: false plus an explicit ignored_paths list. Note that ls_workspace_folders does not bypass it — the rescoped pattern is matched against project-root-relative paths.
Environment
serena-agent 1.6.1, installed via uvx, macOS (arm64), Python 3.12, LSP backend.
Summary
GitignoreParserrescopes patterns from nested.gitignorefiles by prefixing the containing directory's relative path, but does not escape glob metacharacters in that path. A directory whose name contains*therefore produces a pattern that matches far more than it should — in the worst case silently excluding the entire project, so indexing reports 0 files with exit code 0 and no error.Root cause
serena/util/file_system.py,_parse_gitignore_content(v1.6.1, line 272):rel_diris a filesystem name, but it is being interpolated into a pattern context. Lines 263 and 269 have the same issue.Concrete case
A stray uv/venv directory named
***at the project root. Every venv ships a.gitignorewhose entire content is*, so:rel_dir=***,line=****/**/*In gitignore/pathspec syntax
***is just asterisks — a wildcard matching any first segment. So***/**/*means "ignore every path at depth >= 2." All sources undersrc/,packages/, etc. are excluded. Root-level files likepyproject.tomlsurvive, which is why nothing errors.Observed:
Indexing: 0it [00:00, ?it/s]/Indexed files per language:(empty), exit 0. With language auto-detection it instead reportsNo source files for supported language servers were found, which points the user at language configuration — the wrong place entirely.Verified by running
GitignoreParserdirectly against the project: it loads a spec from***/.gitignorewith adjusted pattern***/**/*, andshould_ignore()returns True for 1009 of 1009 tracked.pyfiles.Reproduction
Removing the
***directory, or settingignore_all_files_in_gitignore: false, indexes normally.Impact
Silent and misdiagnosing. Serena appears configured and healthy,
project.ymllooks correct, exit code is 0 — but every symbol tool (find_symbol,find_referencing_symbols) returns nothing because the index is empty. In our case this went unnoticed for some time and read as a language-server problem. Any directory named with glob metacharacters triggers it; stray venvs named with asterisks are the realistic path, butfoo[1],a{b}and similar would also misbehave.Suggested fix
Escape glob metacharacters in
rel_dirbefore joining, so the directory name is matched literally.pathspechonors backslash-escaped metacharacters —\*\*\*/matches only the literal***directory (confirmed as a workaround). Something equivalent to escaping*?[]{}inrel_dirat all three join sites.A cheaper mitigation, worth having regardless: warn when a loaded gitignore spec excludes 100% of candidate files, rather than reporting an empty index as success.
Workaround
ignore_all_files_in_gitignore: falseplus an explicitignored_pathslist. Note thatls_workspace_foldersdoes not bypass it — the rescoped pattern is matched against project-root-relative paths.Environment
serena-agent 1.6.1, installed via
uvx, macOS (arm64), Python 3.12, LSP backend.