Tools7 min read

Diagnostics

Understand bwslc text diagnostics, JSON diagnostics, and stable BWSL error codes.

Reading Time
7 min
Word Count
1,159
Sections
9
Try It Live

Turn the guide into code

Take the key idea from this page into the playground and validate it in a real shader instead of leaving it as theory.

Open Playground

The bwslc compiler reports diagnostics with a severity, compiler phase, message name, and BWSL... code. Human-readable diagnostics are printed by default. Tooling can request structured JSON with -errors-json.

Single-file JSON keeps the original per-file shape. Batch mode and watch mode wrap those per-file documents in aggregate build reports so tools can compile many shaders without losing individual file context.

Text Diagnostics

Without extra flags, diagnostics are written as formatted text on stderr:

text
Diagnostics: 1 error(s), 0 warning(s)
Error[BWSL1000-6CD49A7E] at line 5, column 9
Expected ';' after expression
Token: '}' (type RIGHT_BRACE)

When a source range is available, the compiler includes nearby source lines and a caret. Stage-level diagnostics can also include the pass and stage that produced the failure.

JSON Diagnostics

Use -errors-json when an editor, CI job, or build tool needs machine-readable output:

bash
bwslc shader.bwsl -errors-json

The long option --errors-json is also accepted. Compatibility aliases -json-errors and --json-errors are recognized as well.

In JSON mode, progress output, timing output, and IR dumps are suppressed so stdout stays parseable. The process exits with a nonzero status when errors remain.

Example output for a missing semicolon:

json
{
  "schemaVersion": 2,
  "tool": "bwslc",
  "version": "0.8.0",
  "success": false,
  "file": "/path/to/shader.bwsl",
  "errorCount": 1,
  "warningCount": 0,
  "diagnostics": [
    {
      "severity": "error",
      "phase": "parse",
      "code": "BWSL1000-6CD49A7E",
      "name": "ParseError",
      "message": "Expected ';' after expression",
      "file": "/path/to/shader.bwsl",
      "line": 5,
      "column": 9,
      "endLine": 5,
      "endColumn": 10,
      "offset": 128,
      "length": 1,
      "token": "}",
      "tokenType": "RIGHT_BRACE",
      "context": [
        { "line": 4, "text": "            output.position = float4(0.0, 0.0, 0.0, 1.0)" },
        { "line": 5, "text": "        }" },
        { "line": 6, "text": "" }
      ]
    }
  ]
}

Batch JSON

When multiple files, a directory, or -manifest is used with -errors-json, stdout contains one aggregate document for the whole batch:

bash
bwslc shaders/ -check -errors-json
json
{
  "schemaVersion": 2,
  "tool": "bwslc",
  "version": "0.8.0",
  "batch": true,
  "success": false,
  "fileCount": 2,
  "succeededCount": 1,
  "failedCount": 1,
  "errorCount": 1,
  "warningCount": 0,
  "files": [
    {
      "success": true,
      "file": "/project/shaders/valid.bwsl",
      "errorCount": 0,
      "warningCount": 0,
      "diagnostics": []
    },
    {
      "success": false,
      "file": "/project/shaders/broken.bwsl",
      "errorCount": 1,
      "warningCount": 0,
      "diagnostics": [
        {
          "severity": "error",
          "phase": "parse",
          "code": "BWSL1000-6CD49A7E",
          "name": "ParseError",
          "message": "Expected ';' after expression",
          "file": "/project/shaders/broken.bwsl"
        }
      ]
    }
  ]
}

The nested files entries use the same fields as single-file diagnostic JSON, but omit the shared schemaVersion, tool, and version header.

Watch JSON

With -watch -errors-json, the compiler stays resident and emits one aggregate JSON document per build event:

bash
bwslc shaders/ -modules modules/ -watch -errors-json
json
{
  "schemaVersion": 2,
  "tool": "bwslc",
  "version": "0.8.0",
  "watch": true,
  "event": "build",
  "buildId": 3,
  "trigger": ["/project/modules/Lighting.bwsl"],
  "removed": [],
  "success": true,
  "fileCount": 1,
  "succeededCount": 1,
  "failedCount": 0,
  "errorCount": 0,
  "warningCount": 0,
  "elapsedMs": 18.4,
  "files": [
    {
      "success": true,
      "file": "/project/shaders/lighting.bwsl",
      "errorCount": 0,
      "warningCount": 0,
      "diagnostics": []
    }
  ]
}

Each watch report is a complete JSON object. Consumers can frame the stdout stream by reading one object at a time.

Schema Fields

Top-level fields:

FieldDescription
schemaVersionDiagnostic JSON schema version. Current value is 2.
toolTool name, currently bwslc.
versionCompiler version string.
successtrue when compilation finished without errors. Warnings do not make this false.
fileInput file. JSON mode normalizes normal input files to absolute paths.
errorCountNumber of error diagnostics.
warningCountNumber of warning diagnostics.
diagnosticsArray of diagnostic records.

Aggregate batch/watch fields:

FieldDescription
batchPresent and true for batch-mode aggregate reports.
watchPresent and true for watch-mode aggregate reports.
eventWatch event kind. Build reports use "build".
buildIdMonotonic watch build number, starting at 1 for the initial build.
triggerWatch paths or labels that caused the rebuild. Empty on the initial build.
removedWatched input files removed since the previous build.
fileCountNumber of files included in this aggregate build report.
succeededCountNumber of files that completed without errors.
failedCountNumber of files that returned a failing result.
elapsedMsWatch rebuild duration in milliseconds.
filesArray of per-file diagnostic documents.

Diagnostic record fields:

FieldDescription
severityerror, warning, note, or hint.
phaseCompiler phase: cli, lex, parse, variant, comptime, lowering, compile, validation, io, compute_graph, or internal.
codeStable diagnostic code, such as BWSL0103 or BWSL1000-6CD49A7E.
nameDiagnostic message identifier, such as ParseError or UnknownOption.
messageUser-facing message after template arguments are applied.
fileSource file for the diagnostic when known. Imported module diagnostics report the resolved module file path.
passPass name for stage-level diagnostics.
stageStage name: vertex, fragment, or compute.
line, column1-based source location when available.
endLine, endColumn1-based end source location when available.
offset, lengthByte offset and length in the input source when available.
token, tokenTypeToken text and lexer token type when the diagnostic points at a token.
contextNearby source lines for editor previews or CI annotations.

Error Code Format

Most diagnostics use a fixed code such as BWSL0103. Some broad diagnostic families add a deterministic fingerprint suffix:

text
BWSL1000-6CD49A7E

For fingerprinted codes, the base code identifies the category and the suffix distinguishes the phase/message identity. Treat the full string as the unique code for a concrete diagnostic, and group by the base prefix when you want category-level handling.

Fingerprint suffixes are used for:

BaseNameWhy
BWSL0000RawInternal/raw messages need a unique identity per message.
BWSL1000ParseErrorParser errors share one category but have many concrete messages.
BWSL1100ComptimeErrorCompile-time evaluation failures can come from different evaluator paths.
BWSL1300LoweringErrorIR lowering failures may originate from many lowering checks.

Code Reference

CodeNamePhaseMeaning
BWSL0000-*RawAnyRaw diagnostic message.
BWSL0100NoInputFileCLINo input file was provided.
BWSL0101VariantExpectsNameValueCLI-variant did not receive name=value.
BWSL0102ValidationModeExpectedCLI-validation was missing or had an unsupported mode.
BWSL0103UnknownOptionCLIAn unknown command-line option was passed.
BWSL0200CouldNotReadFileI/OThe input file could not be read.
BWSL0201CouldNotWriteSpirvI/OA SPIR-V output file could not be written.
BWSL1000-*ParseErrorParseSource syntax or parser validation failed.
BWSL1001NoPipelineFoundParseA compilable pipeline was not found.
BWSL1100-*ComptimeErrorComptimeCompile-time evaluation failed.
BWSL1200VariantResolutionFailedVariantVariant declarations could not be resolved.
BWSL1201VariantSelectionFailedVariantRequested variant values were invalid or incomplete.
BWSL1202VariantReflectionFailedVariantVariant reflection JSON could not be built.
BWSL1203VariantSpecializationFailedVariantThe selected variant pipeline could not be specialized.
BWSL1300-*LoweringErrorLoweringBWSL IR lowering failed.
BWSL1301MaxUserVaryingsExceededLoweringA pass exceeded the 16 user-varying limit.
BWSL1400ShaderStageCompileFailedCompileA shader stage failed compilation.
BWSL1401CrossCompileFailedCompileOptional backend cross-compilation failed.
BWSL1500ValidationStrictToolMissingValidationStrict SPIR-V validation was requested but the validation tool was unavailable.
BWSL1501ValidationAutoToolMissingValidationAuto validation skipped because the validation tool was unavailable.
BWSL1502ValidationFailedValidationSPIR-V validation failed.
BWSL1600ComputeGraphValidationFailedCompute graphCompute graph validation failed.
BWSL9000UnhandledExceptionInternalThe compiler caught an unhandled exception.
BWSL9001UnhandledUnknownExceptionInternalThe compiler caught an unknown unhandled exception.

Integration Tips

  • Use code for stable routing, suppression, or issue matching.
  • Use severity and success for build failure decisions.
  • Use line, column, endLine, endColumn, and context for editor markers.
  • Use pass and stage to attach backend or lowering failures to the right pipeline stage.
  • Use phase to separate command-line, parser, specialization, lowering, backend, and validation problems.
  • For batch and watch integrations, handle the aggregate files array and keep routing errors by each nested file's file field.

See Also