Debug Symbol Resolution Issues
Symbol resolution issues show up as a locate question returning no match, a dependents answer that looks incomplete, or an imports answer missing entries you know exist. This guide walks the diagnosis from question phrasing down to a full index rebuild.
Step 1: Check the question phrasing
Section titled “Step 1: Check the question phrasing”Phrasing picks the recipe. Name the entity type and put paths and symbols in backticks so the classifier locks on — vague phrasing falls back to a weaker semantic search:
# Strong: entity type named, symbol backtickedcanopy answer "where is the function `createPayment` defined?"
# Weak: no type, no backticks — falls back to semantic searchcanopy answer "createPayment location"If the strong form finds the symbol, the index is fine and the original question was under-specified.
Step 2: Confirm the symbol was extracted
Section titled “Step 2: Confirm the symbol was extracted”Ask for the file’s surface and the directory’s symbols:
canopy answer "public surface of `src/lib/payments.ts`"canopy answer "list functions defined in `src/lib/`"If the symbol you expect is absent from both answers, Canopy never extracted it. The usual causes: the file is excluded by an ignore layer, the index is stale, or the file failed to parse.
Step 3: Check the file isn’t excluded
Section titled “Step 3: Check the file isn’t excluded”canopy index --list-ignoredThis prints what would be indexed vs skipped, grouped by top-level directory, without indexing. If your file is in the skip list, one of the ignore layers caught it: the bundled defaults (build artifacts, vendored dependencies), .gitignore, .canopyignore, or an --ignore-pattern glob. Re-run with --no-default-ignore, --no-gitignore, or --no-canopyignore to attribute the skip to a specific layer, then adjust that layer.
Step 4: Check imports and wiring
Section titled “Step 4: Check imports and wiring”For an import you expect but don’t see:
canopy answer "what does `src/api/orders.ts` import?"For reachability — whether anything actually connects to the module:
canopy answer "is `src/lib/payments.ts` reachable?"canopy answer "what depends on `src/lib/payments.ts`?"An unreachable module isn’t necessarily broken: it may be invoked at runtime through a dynamic path, be a new module not yet wired in, or be an intentionally standalone script. Use context to decide whether “dead code” is a real finding.
Step 5: Run the doctor
Section titled “Step 5: Run the doctor”canopy doctorThe report covers install info, index status, and the active backend. If the index is missing or points at a different repo root than you expect, this is where it shows.
Step 6: Bring the index up to date
Section titled “Step 6: Bring the index up to date”canopy index . # incremental — picks up changed filescanopy index . --full # wipe and re-index from scratchUse --full when incremental state is suspect — after large-scale moves, renames across directories, or an interrupted index run. During development, canopy serve --watch re-indexes changed files automatically so the MCP answers stay current.
Known limits of static resolution
Section titled “Known limits of static resolution”- Dynamic imports with computed paths can’t be resolved at index time. A module loaded via a string built at runtime won’t appear as a static edge.
- String-path references (a path mentioned in a config file rather than imported) don’t count as dependents. The dependents answer covers static imports.
These are properties of static analysis, not index defects. When a dependents answer looks short, check whether the missing consumers reference the module dynamically.