Diagnostics
Understand bwslc text diagnostics, JSON diagnostics, and stable BWSL error codes.
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 PlaygroundThe 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:
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:
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:
{
"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:
bwslc shaders/ -check -errors-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:
bwslc shaders/ -modules modules/ -watch -errors-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:
| Field | Description |
|---|---|
schemaVersion | Diagnostic JSON schema version. Current value is 2. |
tool | Tool name, currently bwslc. |
version | Compiler version string. |
success | true when compilation finished without errors. Warnings do not make this false. |
file | Input file. JSON mode normalizes normal input files to absolute paths. |
errorCount | Number of error diagnostics. |
warningCount | Number of warning diagnostics. |
diagnostics | Array of diagnostic records. |
Aggregate batch/watch fields:
| Field | Description |
|---|---|
batch | Present and true for batch-mode aggregate reports. |
watch | Present and true for watch-mode aggregate reports. |
event | Watch event kind. Build reports use "build". |
buildId | Monotonic watch build number, starting at 1 for the initial build. |
trigger | Watch paths or labels that caused the rebuild. Empty on the initial build. |
removed | Watched input files removed since the previous build. |
fileCount | Number of files included in this aggregate build report. |
succeededCount | Number of files that completed without errors. |
failedCount | Number of files that returned a failing result. |
elapsedMs | Watch rebuild duration in milliseconds. |
files | Array of per-file diagnostic documents. |
Diagnostic record fields:
| Field | Description |
|---|---|
severity | error, warning, note, or hint. |
phase | Compiler phase: cli, lex, parse, variant, comptime, lowering, compile, validation, io, compute_graph, or internal. |
code | Stable diagnostic code, such as BWSL0103 or BWSL1000-6CD49A7E. |
name | Diagnostic message identifier, such as ParseError or UnknownOption. |
message | User-facing message after template arguments are applied. |
file | Source file for the diagnostic when known. Imported module diagnostics report the resolved module file path. |
pass | Pass name for stage-level diagnostics. |
stage | Stage name: vertex, fragment, or compute. |
line, column | 1-based source location when available. |
endLine, endColumn | 1-based end source location when available. |
offset, length | Byte offset and length in the input source when available. |
token, tokenType | Token text and lexer token type when the diagnostic points at a token. |
context | Nearby 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:
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:
| Base | Name | Why |
|---|---|---|
BWSL0000 | Raw | Internal/raw messages need a unique identity per message. |
BWSL1000 | ParseError | Parser errors share one category but have many concrete messages. |
BWSL1100 | ComptimeError | Compile-time evaluation failures can come from different evaluator paths. |
BWSL1300 | LoweringError | IR lowering failures may originate from many lowering checks. |
Code Reference
| Code | Name | Phase | Meaning |
|---|---|---|---|
BWSL0000-* | Raw | Any | Raw diagnostic message. |
BWSL0100 | NoInputFile | CLI | No input file was provided. |
BWSL0101 | VariantExpectsNameValue | CLI | -variant did not receive name=value. |
BWSL0102 | ValidationModeExpected | CLI | -validation was missing or had an unsupported mode. |
BWSL0103 | UnknownOption | CLI | An unknown command-line option was passed. |
BWSL0200 | CouldNotReadFile | I/O | The input file could not be read. |
BWSL0201 | CouldNotWriteSpirv | I/O | A SPIR-V output file could not be written. |
BWSL1000-* | ParseError | Parse | Source syntax or parser validation failed. |
BWSL1001 | NoPipelineFound | Parse | A compilable pipeline was not found. |
BWSL1100-* | ComptimeError | Comptime | Compile-time evaluation failed. |
BWSL1200 | VariantResolutionFailed | Variant | Variant declarations could not be resolved. |
BWSL1201 | VariantSelectionFailed | Variant | Requested variant values were invalid or incomplete. |
BWSL1202 | VariantReflectionFailed | Variant | Variant reflection JSON could not be built. |
BWSL1203 | VariantSpecializationFailed | Variant | The selected variant pipeline could not be specialized. |
BWSL1300-* | LoweringError | Lowering | BWSL IR lowering failed. |
BWSL1301 | MaxUserVaryingsExceeded | Lowering | A pass exceeded the 16 user-varying limit. |
BWSL1400 | ShaderStageCompileFailed | Compile | A shader stage failed compilation. |
BWSL1401 | CrossCompileFailed | Compile | Optional backend cross-compilation failed. |
BWSL1500 | ValidationStrictToolMissing | Validation | Strict SPIR-V validation was requested but the validation tool was unavailable. |
BWSL1501 | ValidationAutoToolMissing | Validation | Auto validation skipped because the validation tool was unavailable. |
BWSL1502 | ValidationFailed | Validation | SPIR-V validation failed. |
BWSL1600 | ComputeGraphValidationFailed | Compute graph | Compute graph validation failed. |
BWSL9000 | UnhandledException | Internal | The compiler caught an unhandled exception. |
BWSL9001 | UnhandledUnknownException | Internal | The compiler caught an unknown unhandled exception. |
Integration Tips
- Use
codefor stable routing, suppression, or issue matching. - Use
severityandsuccessfor build failure decisions. - Use
line,column,endLine,endColumn, andcontextfor editor markers. - Use
passandstageto attach backend or lowering failures to the right pipeline stage. - Use
phaseto separate command-line, parser, specialization, lowering, backend, and validation problems. - For batch and watch integrations, handle the aggregate
filesarray and keep routing errors by each nested file'sfilefield.
See Also
- CLI Reference - Full command-line flag reference
- Integration - Build-system and engine integration
- Language Specification - Source-tree spec and BNF grammar