Skip to content

RadEndpoints.Cli 1.0.0-alpha.21 - startup crash on Linux due to Windows-style font path #8

@JKamsker

Description

@JKamsker

Hi there!

I'm Jonas, the developer of InSpectra - an OpenCLI visualizer for .NET CLI tools, much like SwaggerUI or ReDoc but for command-line interfaces instead of REST APIs. You can see it in action at inspectra.kamsker.at, which includes a NuGet tool browser powered by an index I built.

To populate that index, I run InSpectra-Discovery - an automated pipeline that indexes every Spectre.Console.Cli tool published on NuGet. The pipeline installs each tool and invokes two introspection subcommands to extract the command tree:

rad cli opencli
rad cli xmldoc

These commands are part of the OpenCLI spec - a lightweight introspection contract that Spectre.Console.Cli tools can opt into so their command surface becomes machine-readable.

What happened

While indexing RadEndpoints.Cli 1.0.0-alpha.21, the pipeline was unable to extract your tool's command metadata. The tool crashes on startup before any command parsing happens.

The tool crashes before command parsing is reached:

Unhandled exception. System.IO.FileNotFoundException: Could not find file '/tmp/inspectra-untrusted-radendpoints.cli-1.0.0-alpha.21-4aef35e37e1b454892275dbd041befed/tool/.store/radendpoints.cli/1.0.0-alpha.21/radendpoints.cli/1.0.0-alpha.21/tools/net8.0/any/Fonts\Contessa.flf'.
File name: '/tmp/inspectra-untrusted-radendpoints.cli-1.0.0-alpha.21-4aef35e37e1b454892275dbd041befed/tool/.store/radendpoints.cli/1.0.0-alpha.21/radendpoints.cli/1.0.0-alpha.21/tools/net8.0/any/Fonts\Contessa.flf'
   at Interop.ThrowExceptionForIoErrno(ErrorInfo errorInfo, String path, Boolean isDirError)
   at Microsoft.Win32.SafeHandles.SafeFileHandle.Open(String path, OpenFlags flags, Int32 mode, Boolean failForSymlink, Boolean& wasSymlink, Func`4 createOpenException)
   at Microsoft.Win32.SafeHandles.SafeFileHandle.Open(String fullPath, FileMode mode, FileAccess access, FileShare share, FileOptions options, Int64 preallocationSize, UnixFileMode openPermissions, Int64& fileLength, UnixFileMode& filePermissions, Boolean failForSymlink, Boolean& wasSymlink, Func`4 createOpenException)
   at System.IO.Strategies.OSFileStreamStrategy..ctor(String path, FileMode mode, FileAccess access, FileShare share, FileOptions options, Int64 preallocationSize, Nullable`1 unixCreateMode)
   at System.IO.StreamReader.ValidateArgsAndOpenPath(String path, Encoding encoding, Int32 bufferSize)
   at System.IO.File.ReadAllText(String path, Encoding encoding)
   at Spectre.Console.FigletFont.Load(String path) in /_/src/Spectre.Console/Widgets/Figlet/FigletFont.cs:line 83
   at RadEndpoints.Cli.Helpers.RadHelper.RenderLogo(String text, String fontPath) in /home/runner/work/RadEndpoints/RadEndpoints/RadEndpoints.Cli/Helpers/RadHelper.cs:line 25
   at Program.<Main>$(String[] args) in /home/runner/work/RadEndpoints/RadEndpoints/RadEndpoints.Cli/Program.cs:line 9

This appears to be a runtime issue in the tool itself (not related to InSpectra). The root cause is a Windows-style backslash in the font file path. In FontConstants.cs, the path is defined as @"Fonts\Contessa.flf" - on Windows, Path.Combine normalizes this correctly, but on Linux/macOS the backslash is treated as a literal character in the filename rather than a directory separator. The resulting path ends with Fonts\Contessa.flf (a single component) instead of Fonts/Contessa.flf (directory + file), so the file is never found. Because RenderLogo is called at line 9 of Program.cs - before the CommandApp is even constructed - the tool crashes immediately on any Linux or macOS system regardless of what arguments are passed.

A quick fix would be to replace the backslash with Path.Combine or Path.DirectorySeparatorChar:

// FontConstants.cs - before
public static string FontPath => @"Fonts\Contessa.flf".GetAssemblyRootedPath();

// FontConstants.cs - after
public static string FontPath => Path.Combine("Fonts", "Contessa.flf").GetAssemblyRootedPath();

The same pattern appears in GenerateEndpointCommand.cs for the template paths (@"Templates\Endpoint.txt", @"Templates\Models.txt", @"Templates\Mapper.txt"), which would hit the same issue on Linux when those code paths are reached.

What would help

The primary ask is fixing the cross-platform path issue described above so the tool can run on Linux and macOS. That alone would unblock our indexing pipeline (and any Linux/macOS users of the tool).

As a secondary note: your project currently references Spectre.Console.Cli 0.48.0. The cli xmldoc command has been a built-in hidden command in Spectre.Console since its very early days (December 2020), and cli opencli was added in v0.52.0. Upgrading to the latest Spectre.Console.Cli would give you both commands out of the box - no code changes needed. However, the logo rendering would need to happen after command parsing (or be guarded so it does not run for introspection subcommands), otherwise it would still run before Spectre gets a chance to dispatch the built-in commands.

PS: I'm working on a GitHub Action to auto-generate purpose-built InSpectra pages for your repo, like this: Example If you're interested, you can find the exact commands buried in my CI, or come back in a few days when I have the easy documentation ready.

Links

Thanks for your time!

- Jonas

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions