altool IsSymbolOnly / IsRuntimePackage return exit code 1 when the answer is "False", making a negative result indistinguishable from an error
Nobody has claimed this yet.
- Dominant language
- PowerShell
- Stars
- 881
- Forks
- 285
- Avg merge
- 3d 36m
- Merged PRs (30d)
- 1
Description
1. Describe the bug
The IsSymbolOnly and IsRuntimePackage commands in ALTool (altool.exe / the al alias from the Microsoft.Dynamics.BusinessCentral.Development.Tools NuGet package) encode their boolean answer in the process exit code: True → exit code 0, False → exit code 1.
This is wrong for two reasons:
- By long-standing convention (Win32
ERROR_SUCCESS= 0, and the .NETEnvironment.ExitCode/ Windows system error codes documentation), a non-zero exit code indicates that the process failed. A check that ran successfully and determined the answer is "False" did not fail. - Critically, genuine errors (e.g., the input file does not exist) also return exit code 1. A calling program therefore cannot distinguish "the package is not symbol-only" from "the tool failed to check at all" without parsing stdout/stderr text, which defeats the purpose of these commands for CI/CD scenarios. Per the documentation, these checks exist specifically to "help tools like AL-Go determine if an extension can be published to SaaS or containers" ΓÇö i.e., they are designed to be called from other programs, where this matters most.
The same problem exists for both IsSymbolOnly and IsRuntimePackage.
2. To Reproduce
Steps to reproduce the behavior (PowerShell, using any regular AL extension package):
# 1. Install the tools package
dotnet tool install --global Microsoft.Dynamics.BusinessCentral.Development.Tools --prerelease
# 2. Take any normal (non-symbol-only) extension, e.g. the output of a regular 'al compile',
# and create a symbol-only variant of it for comparison:
al CreateSymbolPackage "MyApp.app" "MyApp.symbols.app"
# 3. Check the normal package ΓÇö the check succeeds, answer is False, but exit code is 1:
al IsSymbolOnly "MyApp.app"
$LASTEXITCODE # -> 1, output: "Extension is symbol-only: False"
# 4. Check the symbol-only package ΓÇö answer is True, exit code is 0:
al IsSymbolOnly "MyApp.symbols.app"
$LASTEXITCODE # -> 0, output: "Extension is symbol-only: True"
# 5. Now trigger a genuine error ΓÇö the exit code is ALSO 1, identical to the "False" case:
al IsSymbolOnly "DoesNotExist.app"
$LASTEXITCODE # -> 1, output: "The specified input package file does not exist."
# IsRuntimePackage behaves the same way:
al IsRuntimePackage "MyApp.app"
$LASTEXITCODE # -> 1, output: "Extension is runtime package: False"
Note: This issue is about the command-line tool, so the repro is a shell session rather than an AL snippet; any .app file reproduces it.
3. Expected behavior
The exit code should reflect whether the command succeeded, not what the boolean answer was:
- Exit code 0 whenever the check completed successfully, with the answer reported on stdout (
Extension is symbol-only: True/False) ΓÇö machine-readable output such as--format jsonwould be a welcome bonus. - A non-zero exit code only when the tool actually failed (file not found, corrupt package, bad arguments, ...).
Alternatively, if encoding the answer in the exit code is intentional, error cases must use a distinct, documented exit code (e.g., 0 = True, 1 = False, 2+ = error) so callers can tell the three outcomes apart. Currently False and "error" are both 1, which makes the exit code unusable.
4. Actual behavior
| Scenario | Output | Exit code |
|---|---|---|
IsSymbolOnly on a symbol-only package |
Extension is symbol-only: True |
0 |
IsSymbolOnly on a regular package |
Extension is symbol-only: False |
1 |
IsSymbolOnly on a non-existent file |
The specified input package file does not exist. |
1 |
IsRuntimePackage on a runtime package |
Extension is runtime package: True |
0 |
IsRuntimePackage on a non-runtime package |
Extension is runtime package: False |
1 |
A successful check that answers "False" is reported as a process failure, and it is indistinguishable from a real error.
5. Versions:
- AL Language: ALTool 18.0.37.11445+488e56099dcfd36fbaad2b886e2d17a85ca69552 (
Microsoft.Dynamics.BusinessCentral.Development.Tools18.0.37.11445-beta, installed as a global .NET tool) - Visual Studio Code: N/A ΓÇö reproduced directly from the command line with the Development Tools NuGet package
- Business Central: N/A (offline package inspection)
- List of Visual Studio Code extensions that you have installed: N/A
- Operating System:
- Windows
- Linux
- MacOS
Final Checklist
Please remember to do the following:
-
Search the issue repository to ensure you are reporting a new issue
-
Reproduce the issue after disabling all extensions except the AL Language extension
-
Simplify your code around the issue to better isolate the problem
This bug report was created with the help of AI, but I was able to reproduce the problem.
Internal work item: AB#648585
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start at the ALTool command entry points for IsSymbolOnly and IsRuntimePackage, using the PowerShell reproduction in this issue to trace how successful False results and genuine errors set the process exit code. Verify both commands and error cases, then confirm that successful checks return 0 while failures remain non-zero and the existing stdout answers are preserved.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- powershell
- Domain
- cli
- Issue type
- Bug
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Quiet
- Clarity
- Clearly specified
- Newbie friendliness
- 58/100