spectreconsole/spectre.console · error · InvalidOperationException
Failed to read spinners_default.json at {file.Path}
Error message
Failed to read spinners_default.json at {file.Path} What it means
Thrown inside the spinner source generator when an AdditionalFiles entry ending in spinners_default.json matched but GetText returned null. The default spinner set is required (the generator returns an empty array if either default or sindresorhus data is missing, but the per-file read failure still throws first). It is a compile-time InvalidOperationException in the generator pipeline.
Source
Thrown at src/Spectre.Console.SourceGenerator/Spinners/SpinnerGenerator.cs:29
/// </summary>
[Generator]
public class SpinnerGenerator : IIncrementalGenerator
{
// UTF-8 without a BOM, matching the repository's source file convention
// and keeping the checked-in generated files deterministic.
private static readonly Encoding Utf8NoBom = new UTF8Encoding(encoderShouldEmitUTF8Identifier: false);
/// <inheritdoc />
public void Initialize(IncrementalGeneratorInitializationContext context)
{
// Find spinners_default.json
// Step 1: Extract text (cached by string value equality)
// Step 2: Wrap in EquatableArray for value equality when combining
var defaultSpinners = context.AdditionalTextsProvider
.Where(static file => file.Path.EndsWith("spinners_default.json", StringComparison.OrdinalIgnoreCase))
.Select(static (file, ct) =>
file.GetText(ct)?.ToString()
?? throw new InvalidOperationException($"Failed to read spinners_default.json at {file.Path}"))
.Collect()
.Select(static (arr, _) => new EquatableArray<string>(arr));
// Find spinners_sindresorhus.json
var sindreSpinners = context.AdditionalTextsProvider
.Where(static file => file.Path.EndsWith("spinners_sindresorhus.json", StringComparison.OrdinalIgnoreCase))
.Select(static (file, ct) =>
file.GetText(ct)?.ToString()
?? throw new InvalidOperationException($"Failed to read spinners_sindresorhus.json at {file.Path}"))
.Collect()
.Select(static (arr, _) => new EquatableArray<string>(arr));
// Combine both JSON files and parse in the pipeline (for caching)
// EquatableArray has value equality, so this step is properly cached
var spinners = defaultSpinners.Combine(sindreSpinners)
.Select(static (data, _) =>
{
var (defaultJsonFiles, sindreJsonFiles) = data;View on GitHub (pinned to 0acc92fada)
Solutions
- Clean rebuild (dotnet clean && dotnet build) to re-read AdditionalFiles
- Confirm spinners_default.json exists and is readable on disk
- Restore/reinstall the Spectre.Console package to refresh the file
- Release any process lock on spinners_default.json
Example fix
# before: spinners_default.json unreadable during generation # after: clean generation dotnet clean dotnet restore dotnet build
Defensive patterns
Strategy: validation
Validate before calling
// Pre-build check: confirm spinners_default.json AdditionalFiles item resolves dotnet msbuild -getItem:AdditionalFiles | findstr spinners_default.json
Prevention
- Do not hand-edit generator data files
- CI step failing on zero-byte/missing data files prevents broken builds
When it happens
Trigger: The spinners_default.json AdditionalFiles item is in the graph but its text cannot be read at generation time (locked, deleted mid-build, unreadable, empty).
Common situations: Corrupted spinners_default.json; antivirus/IDE lock; partial checkout; package restore that left the file missing or zero-byte.
Related errors
- Failed to read spinners_sindresorhus.json at {file.Path}
- Failed to read colors.json at {file.Path}
- Failed to read emoji.json at {file.Path}
- Color {number} has null name
- Color {number} has null alias
AI-assisted analysis of spectreconsole/spectre.console@0acc92fada (2026-08-13).
Data as JSON: /api/errors/749f153ed20707ff.
Report an issue: GitHub.