Skip to content

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

@ytymo

Description

@ytymo

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
BuildDescriptorsAppendMembers, and for each KeySymbol calls
SymbolDescriptor.CreateSymbolDisplayVisitor.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 al_symbolsearch fails after al_addproject #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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions