microsoft / microsoft/AL

al_symbolsearch (AL MCP server) crashes with NullReferenceException on any scope=dependencies / scope=all query

Open
#8,270 0 comments 1 reaction 0 assignees View on GitHub

Nobody has claimed this yet.

accepted al-tools
Dominant language
PowerShell
Stars
881
Forks
285
Avg merge
3d 36m
Merged PRs (30d)
1

Description

Describe the bug

The AL MCP server tool al_symbolsearch deterministically crashes for any query whose
scope includes dependency symbols (filters.scope = "dependencies", or the default
"all" whenever the result must include a dependency-side object). The MCP client only
receives the generic An error occurred invoking 'al_symbolsearch'; the server stderr
shows an unhandled System.NullReferenceException thrown while building symbol
descriptors for dependency keys.

scope=project works fine. The companion tool al_getpackagedependencies returns all
referenced packages correctly, so the symbols are loaded ΓÇö the failure is purely inside
al_symbolsearch's dependency descriptor-build path, while rendering a table Key.

This is not the same as #8227 (which is a session/caching issue after
al_addproject, has no stack trace, and is resolved by /mcp reload). The crash here is
a hard NullReferenceException that reproduces on a freshly started server with no
al_addproject/al_downloadsymbols in the session, and is not resolved by reload or
by re-downloading symbols.

Stack trace (captured from server stderr)

System.NullReferenceException: Object reference not set to an instance of an object.
   at Microsoft.Dynamics.Nav.CodeAnalysis.Symbols.ReferenceKeySymbol.AppendFieldMembers(PooledNameObjectDictionary`1 fields, ContainerSymbol table) in X:\source\Prod\Microsoft.Dynamics.Nav.CodeAnalysis\Symbols\Reference\ReferenceKeySymbol.cs:line 83
   at Microsoft.Dynamics.Nav.CodeAnalysis.Symbols.ReferenceKeySymbol.GetLazyFields() in X:\source\Prod\Microsoft.Dynamics.Nav.CodeAnalysis\Symbols\Reference\ReferenceKeySymbol.cs:line 60
   at System.Lazy`1.CreateValue()
   at Microsoft.Dynamics.Nav.CodeAnalysis.SymbolDisplayVisitor.VisitKey(KeySymbol symbol) in X:\source\Prod\Microsoft.Dynamics.Nav.CodeAnalysis\SymbolDisplay\SymbolDisplayVisitor.cs:line 897
   at Microsoft.Dynamics.Nav.CodeAnalysis.Workspaces.LanguageModelTools.SymbolSearch.SymbolSearchService.SymbolDescriptor.Create(Symbol symbol, Symbol containerSymbol, SymbolSearchScope scope, Boolean isTopLevel, CancellationToken cancellationToken) in X:\source\Prod\Microsoft.Dynamics.Nav.CodeAnalysis.Workspaces\LanguageModelTools\SymbolSearch\SymbolSearchService.cs:line 606
   at Microsoft.Dynamics.Nav.CodeAnalysis.Workspaces.LanguageModelTools.SymbolSearch.SymbolSearchService.AppendMembers(Builder builder, ContainerSymbol container, Symbol rootContainer, SymbolSearchScope scope, CancellationToken cancellationToken) in ...SymbolSearchService.cs:line 202
   at ...SymbolSearchService.BuildDescriptors(IEnumerable`1 topLevelSymbols, SymbolSearchScope scope, CancellationToken cancellationToken) in ...SymbolSearchService.cs:line 184
   at ...SymbolSearchService.GetDependencyDescriptorsAsync(Compilation compilation, CancellationToken cancellationToken) in ...SymbolSearchService.cs:line 152
   at ...SymbolSearchService.SearchAsync(ProjectId projectId, SymbolSearchParameters parameters, CancellationToken cancellationToken) in ...SymbolSearchService.cs:line 76
   at Microsoft.Dynamics.BusinessCentral.ALMcp.Services.SymbolSearchToolService.SearchAsync(...) in ...almcp\Services\SymbolSearchToolService.cs:line 52

Likely root cause

GetDependencyDescriptorsAsync walks every top-level dependency symbol via
BuildDescriptors → AppendMembers, and for each KeySymbol calls
SymbolDescriptor.Create → SymbolDisplayVisitor.VisitKey, which forces
ReferenceKeySymbol.GetLazyFields() → AppendFieldMembers. For at least one key in the
Microsoft Base Application symbol set, a field reference resolves to null and
AppendFieldMembers (ReferenceKeySymbol.cs:83) dereferences it without a guard, throwing
NullReferenceException and aborting the entire dependency walk.

Because descriptors are built before the query / kinds / objectName / limit
filters are applied, no query narrowing avoids the bad key ΓÇö every dependency-scope call
fails the same way.

Suggested fix: null-guard in ReferenceKeySymbol.AppendFieldMembers (and/or
SymbolDisplayVisitor.VisitKey) so an unresolved key-field is skipped instead of
crashing; ideally also isolate per-symbol descriptor failures in BuildDescriptors so
one bad symbol can't abort the whole result set.

To Reproduce

  1. Any AL project whose .alpackages contains Microsoft Base Application 28.0
    (28.0.46665.50632) + System Application 28.0 symbols.
  2. Start the MCP server:
    altool.exe launchmcpserver <project> --transport stdio --packagecachepath <.alpackages>
  3. Invoke al_symbolsearch with a dependency-scoped query, e.g.:
    { "name": "al_symbolsearch",
      "arguments": { "parameters": {
        "query": "Customer",
        "filters": { "scope": "dependencies", "kinds": ["Table"], "limit": 3 } } } }
    

Expected: matching dependency tables returned.
Actual: {"content":[{"type":"text","text":"An error occurred invoking 'al_symbolsearch'."}],"isError":true}; server stderr logs the NullReferenceException above.

What was ruled out

  • Not a result-size/timeout issue. Tight limit and specific query crash identically; the crash is in descriptor build, before filtering. (An OperationCanceledException only appears if the client closes stdin mid-request ΓÇö that is a shutdown artifact, not the bug.)
  • Not query-narrowable. objectName="Customer", memberKinds=["Field"], scope=dependencies crashes the same way.
  • Not fixed by re-downloading symbols. Wiping .alpackages and re-running al_downloadsymbols force=true returned byte-identical Base Application 28.0.46665.50632; the crash persists ΓÇö confirming the defect is in the symbol renderer, not the symbol data.
  • Not #8227. No al_addproject involved; /mcp reload does not help; a stack trace is present.

Environment

  • AL VS Code extension: ms-dynamics-smb.al-17.0.2273547
  • altool version: 17.0.34.45391+89ddc161d3e4421fa7ecef442abf29ca6e6ebfba
  • OS: Windows 11 Pro 26200
  • Dependency symbols: Microsoft Base Application / System Application 28.0.46665.50632, System 28.0.50354, Application/Business Foundation 28.0.46665.48257
  • Transport: stdio
    Internal work item: AB#638487

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with ReferenceKeySymbol.cs at AppendFieldMembers line 83, then trace GetLazyFields through SymbolDisplayVisitor.VisitKey and SymbolSearchService.SymbolDescriptor.Create. Reproduce with the dependency-scoped al_symbolsearch request against the specified Base and System Application symbols. Done means dependency searches return matching tables instead of an unhandled NullReferenceException, while unresolved key fields no longer abort descriptor construction.

Written by the indexing model from the issue text.

Assessment

Tech stack
csharp
Domain
tooling
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
48/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.