📊 Error Message Quality Analysis
Analysis Date: 2026-03-12
Test Cases: 3
Average Score: 62.7/100
Status: ⚠️ Needs Improvement (below threshold of 70)
Executive Summary
Static analysis of the gh-aw compiler's error message quality across three error categories reveals an average score of 62.7/100, below the quality threshold of 70. One test case (YAML syntax errors) scored 44/100, breaching the critical threshold of 55. While the engine name validation error messages are excellent (80/100), YAML syntax errors suffer from wrong line positions, technical jargon, message duplication, and no corrective guidance. Schema validation errors for unknown properties are acceptable but lack examples or valid-value lists.
Key Findings:
- Strengths: Engine validation errors have excellent "Did you mean" + example + docs link; schema errors show accurate source context with visual pointers
- Weaknesses: YAML errors always report
1:1 for position (wrong); no corrective hints or examples for YAML and schema errors; Hint field in CompilerError struct is never rendered by FormatError()
- Critical Issues: YAML frontmatter syntax errors produce confusing output: wrong outer line number, technical YAML parser jargon, and duplicated error message content due to
fmt.Errorf("%s: %w", formattedErr, cause) chaining
Test Case Results
Test Case 1: Invalid YAML Syntax (workflow-generator.md) – Score: 44/100 ❌
Test Configuration
Workflow: .github/workflows/workflow-generator.md (112 lines, simple)
Error Type: Category A – Invalid YAML syntax
Error Introduced: Line 14: engine copilot (missing colon – should be engine: copilot)
Compiler Output (reconstructed from source analysis)
The error flows through:
pkg/parser/frontmatter_content.go:68 – goccy YAML error wrapped as "failed to parse frontmatter:\n[14:8]: mapping value is not allowed in this context\n > 14 | engine copilot\n ^"
pkg/workflow/compiler.go:84 – wrapped via formatCompilerError(markdownPath, "error", err.Error(), err) with hardcoded Line:1, Column:1
pkg/workflow/compiler_error_formatter.go:32 – cause chained as fmt.Errorf("%s: %w", formattedErr, cause) → duplicates the error text
workflow-generator.md:1:1: error: failed to parse frontmatter:
[14:8]: mapping value is not allowed in this context
12 | contents: read
13 | issues: read
> 14 | engine copilot
^
15 | pull-requests: read
: failed to parse frontmatter:
[14:8]: mapping value is not allowed in this context ← DUPLICATED
...
```
#### Evaluation Scores
| Dimension | Score | Rating |
|-----------|-------|--------|
| Clarity | 14/25 | Poor |
| Actionability | 8/25 | Poor |
| Context | 13/20 | Acceptable |
| Examples | 2/15 | Critical |
| Consistency | 7/15 | Poor |
| **Total** | **44/100** | **❌ Critical** |
#### Strengths
- ✅ goccy YAML error includes correct inner line number and source context with `^` pointer
- ✅ Shows problematic source line
#### Weaknesses
- ❌ Outer position is always `file:1:1` (incorrect – error is at line 14)
- ❌ Technical YAML jargon: "mapping value is not allowed in this context" – confusing to non-YAML experts
- ❌ Error message is duplicated due to `fmt.Errorf("%s: %w", formattedErr, cause)` wrapping in `compiler_error_formatter.go:32`
- ❌ Two conflicting formats in the same output: outer `file:1:1:` + inner `[14:8]:`
- ❌ No suggestion or example of correct syntax
#### Improvement Suggestions
1. **Extract accurate line/col from the goccy YAML error before wrapping**:
```go
// In compiler.go, instead of:
return formatCompilerError(markdownPath, "error", err.Error(), err)
// Use position extracted from the YAML error:
line, col := extractPositionFromYAMLError(err)
return formatCompilerErrorWithPosition(markdownPath, line, col, "error", err.Error(), nil)
```
2. **Prevent message duplication** – pass `nil` as cause when the message already includes the error:
```go
// compiler_error_formatter.go line 32: Only chain cause when it adds NEW information
// Currently duplicates content since message = err.Error()
```
3. **Translate common YAML errors to plain language** in `pkg/parser/yaml_error.go`:
- `"mapping value is not allowed in this context"` → `"Missing ':' after key (e.g., 'engine copilot' should be 'engine: copilot')"`
- `"did not find expected key"` → `"Incorrect indentation or missing key"`
4. **Add corrective example for missing colon errors**:
```
Correct syntax:
engine: copilot
```
</details>
<details>
<summary><b>Test Case 2: Invalid Engine Name (cli-version-checker.md)</b> – Score: 80/100 ✅</summary>
#### Test Configuration
**Workflow**: `.github/workflows/cli-version-checker.md` (342 lines, medium)
**Error Type**: Category B – Invalid engine name
**Error Introduced**: `engine: copiilot` (typo – double 'i', should be `copilot`)
#### Compiler Output (reconstructed from source analysis)
Source: `pkg/workflow/engine_validation.go:235` via `validateEngine("copiilot")`
```
cli-version-checker.md:1:1: error: invalid engine: copiilot. Valid engines are: claude, codex, copilot.
Did you mean: copilot?
Example:
engine: copilot
See: https://github.com/github/gh-aw/blob/main/docs/src/content/docs/reference/engines.md
```
#### Evaluation Scores
| Dimension | Score | Rating |
|-----------|-------|--------|
| Clarity | 22/25 | Excellent |
| Actionability | 22/25 | Excellent |
| Context | 11/20 | Acceptable |
| Examples | 13/15 | Excellent |
| Consistency | 12/15 | Good |
| **Total** | **80/100** | **✅ Good** |
#### Strengths
- ✅ Lists all valid engines in the error message
- ✅ "Did you mean: copilot?" via Levenshtein distance fuzzy matching
- ✅ Shows correct usage example: `engine: copilot`
- ✅ Links to documentation
#### Weaknesses
- ⚠️ Position is always `file:1:1` (the engine field is not at line 1 – should detect actual line)
- ⚠️ No source code context shown (no `Context` field populated)
#### Improvement Suggestions
1. **Populate source context** – read the source file and add surrounding lines to show where `engine: copiilot` appears
2. **Use accurate line position** – detect the line where `engine:` is defined in the frontmatter
</details>
<details>
<summary><b>Test Case 3: Invalid Permissions Scope (pr-triage-agent.md)</b> – Score: 64/100 ⚠️</summary>
#### Test Configuration
**Workflow**: `.github/workflows/pr-triage-agent.md` (450 lines, complex)
**Error Type**: Category C – Invalid configuration field
**Error Introduced**: `permissions: { unknown-scope: read }` (invalid permission scope)
#### Compiler Output (reconstructed from source analysis)
Source: `pkg/parser/schema_errors.go:223` → `rewriteAdditionalPropertiesError()` → `formatCompilerErrorWithPosition()`
```
pr-triage-agent.md:4:3: error: Unknown property: unknown-scope
2 | permissions:
> 3 | unknown-scope: read
| ^^^^^^^^^^^^^
4 | ---
Evaluation Scores
| Dimension |
Score |
Rating |
| Clarity |
21/25 |
Excellent |
| Actionability |
10/25 |
Poor |
| Context |
17/20 |
Excellent |
| Examples |
3/15 |
Critical |
| Consistency |
13/15 |
Good |
| Total |
64/100 |
⚠️ Acceptable |
Strengths
- ✅ Accurate file:line:col position
- ✅ Source code context with visual pointer (
^^^^^)
- ✅ Clear "Unknown property" wording
Weaknesses
- ❌ No list of valid permission scopes (contents, issues, pull-requests, etc.)
- ❌ Hints intentionally removed (
// Hints removed as per requirements in schema_compiler.go)
- ❌ No example of valid permissions configuration
- ❌ User left with no guidance on what valid values are
Improvement Suggestions
-
List valid values for known enumerations – for permissions, enumerate valid scopes:
Unknown property: unknown-scope.
Valid permission scopes: actions, attestations, checks, contents, deployments,
discussions, id-token, issues, packages, pages, pull-requests, security-events,
statuses, workflows.
```
-
Re-evaluate the "hints removed" policy – at minimum, add valid-value lists without free-form hints
-
Add a compact example:
Example:
permissions:
contents: read
issues: write
Overall Statistics
| Metric |
Value |
| Tests Run |
3 |
| Average Score |
62.7/100 |
| Excellent (85+) |
0 |
| Good (70-84) |
1 (Test 2: engine name) |
| Acceptable (55-69) |
1 (Test 3: permissions) |
| Poor / Critical (<55) |
1 (Test 1: YAML syntax) |
Quality Assessment: ❌ Needs Improvement (Average 62.7/100, below threshold of 70; Test Case 1 breaches critical threshold of 55)
Priority Improvement Recommendations
🔴 High Priority
1. Fix wrong line:col in formatCompilerError fallback path
All errors routed through formatCompilerError() in compiler_error_formatter.go hardcode Line: 1, Column: 1. This affects YAML syntax errors, engine validation, and many others.
- File:
pkg/workflow/compiler.go + pkg/workflow/compiler_error_formatter.go
- Fix: Extract position from the underlying error before falling back to
1:1; or at minimum pass 0 to suppress the misleading position
- Impact: Fixes misleading
file:1:1 that causes IDE integrations to jump to wrong location
2. Fix YAML error message duplication
In pkg/workflow/compiler_error_formatter.go:32:
// CURRENT (causes duplication when message = err.Error()):
return fmt.Errorf("%s: %w", formattedErr, cause)
// SUGGESTED FIX – only chain when cause adds new information:
if cause != nil && cause.Error() != message {
return fmt.Errorf("%s: %w", formattedErr, cause)
}
return errors.New(formattedErr)
3. Translate YAML parser jargon to plain English
In pkg/parser/yaml_error.go, add a translation layer for common goccy/go-yaml error patterns:
var yamlErrorTranslations = []struct {
pattern string
replacement string
}{
{"mapping value is not allowed in this context", "unexpected value – did you forget a ':' after a key?"},
{"did not find expected key", "incorrect indentation or missing key name"},
{"could not find expected ':'", "missing ':' between key and value"},
{"found character that cannot start any token", "invalid character – check indentation uses spaces, not tabs"},
}
🟡 Medium Priority
4. Implement Hint field rendering in FormatError()
The Hint field is defined in console.CompilerError but never rendered by FormatError() in pkg/console/console.go. This means any code that sets Hint silently discards the hint.
// Add after context rendering in FormatError() (pkg/console/console.go ~line 74):
if err.Hint != "" {
output.WriteString(applyStyle(styles.Info, "hint: "))
output.WriteString(err.Hint)
output.WriteString("\n")
}
5. Add valid-values lists to schema validation errors for known enumerations
In pkg/parser/schema_errors.go, when an additionalProperties error occurs on a well-known field like permissions, append the valid values:
var knownFieldValidValues = map[string]string{
"permissions": "Valid scopes: actions, contents, issues, pull-requests, ...",
"engine": "Valid values: copilot, claude, codex (see engine validation)",
}
🟢 Low Priority
6. Add source context to engine/semantic validation errors
Engine validation errors and other semantic errors use formatCompilerError() which doesn't populate Context (source lines). Reading the source file to extract the relevant lines would improve these messages:
// After reading the workflow file, extract context lines and pass to console.CompilerError
context, line, col := extractContextFromSource(markdownPath, "engine:")
Implementation Guide
Files to Modify
| File |
Change |
pkg/console/console.go |
Add Hint field rendering in FormatError() after context block |
pkg/workflow/compiler_error_formatter.go |
Fix duplication: don't chain cause when message == cause.Error() |
pkg/workflow/compiler.go |
Extract actual line/col from YAML errors before calling formatCompilerError |
pkg/parser/yaml_error.go |
Add YAML jargon translation map + apply before returning formatted error |
pkg/parser/schema_errors.go |
Append valid-value hints for known field enumerations |
Success Metrics
- YAML syntax errors: Outer
file:line:col matches actual error line (not 1:1)
- YAML syntax errors: Message appears once (no duplication)
- Schema errors: Valid-value lists included for permission scopes and other enumerations
- All errors:
Hint field is rendered when set
- Average quality score: ≥ 70/100 on next daily check
References:
Generated by Daily Syntax Error Quality Check workflow
Next check: Runs daily
Generated by Daily Syntax Error Quality Check · ◷
📊 Error Message Quality Analysis
Analysis Date: 2026-03-12⚠️ Needs Improvement (below threshold of 70)
Test Cases: 3
Average Score: 62.7/100
Status:
Executive Summary
Static analysis of the
gh-awcompiler's error message quality across three error categories reveals an average score of 62.7/100, below the quality threshold of 70. One test case (YAML syntax errors) scored 44/100, breaching the critical threshold of 55. While the engine name validation error messages are excellent (80/100), YAML syntax errors suffer from wrong line positions, technical jargon, message duplication, and no corrective guidance. Schema validation errors for unknown properties are acceptable but lack examples or valid-value lists.Key Findings:
1:1for position (wrong); no corrective hints or examples for YAML and schema errors;Hintfield inCompilerErrorstruct is never rendered byFormatError()fmt.Errorf("%s: %w", formattedErr, cause)chainingTest Case Results
Test Case 1: Invalid YAML Syntax (workflow-generator.md) – Score: 44/100 ❌
Test Configuration
Workflow:
.github/workflows/workflow-generator.md(112 lines, simple)Error Type: Category A – Invalid YAML syntax
Error Introduced: Line 14:
engine copilot(missing colon – should beengine: copilot)Compiler Output (reconstructed from source analysis)
The error flows through:
pkg/parser/frontmatter_content.go:68– goccy YAML error wrapped as"failed to parse frontmatter:\n[14:8]: mapping value is not allowed in this context\n > 14 | engine copilot\n ^"pkg/workflow/compiler.go:84– wrapped viaformatCompilerError(markdownPath, "error", err.Error(), err)with hardcodedLine:1, Column:1pkg/workflow/compiler_error_formatter.go:32– cause chained asfmt.Errorf("%s: %w", formattedErr, cause)→ duplicates the error textEvaluation Scores
Strengths
^^^^^)Weaknesses
// Hints removed as per requirementsinschema_compiler.go)Improvement Suggestions
List valid values for known enumerations – for
permissions, enumerate valid scopes:Re-evaluate the "hints removed" policy – at minimum, add valid-value lists without free-form hints
Add a compact example:
Overall Statistics
Quality Assessment: ❌ Needs Improvement (Average 62.7/100, below threshold of 70; Test Case 1 breaches critical threshold of 55)
Priority Improvement Recommendations
🔴 High Priority
1. Fix wrong line:col in
formatCompilerErrorfallback pathAll errors routed through
formatCompilerError()incompiler_error_formatter.gohardcodeLine: 1, Column: 1. This affects YAML syntax errors, engine validation, and many others.pkg/workflow/compiler.go+pkg/workflow/compiler_error_formatter.go1:1; or at minimum pass0to suppress the misleading positionfile:1:1that causes IDE integrations to jump to wrong location2. Fix YAML error message duplication
In
pkg/workflow/compiler_error_formatter.go:32:3. Translate YAML parser jargon to plain English
In
pkg/parser/yaml_error.go, add a translation layer for common goccy/go-yaml error patterns:🟡 Medium Priority
4. Implement
Hintfield rendering inFormatError()The
Hintfield is defined inconsole.CompilerErrorbut never rendered byFormatError()inpkg/console/console.go. This means any code that setsHintsilently discards the hint.5. Add valid-values lists to schema validation errors for known enumerations
In
pkg/parser/schema_errors.go, when anadditionalPropertieserror occurs on a well-known field likepermissions, append the valid values:🟢 Low Priority
6. Add source context to engine/semantic validation errors
Engine validation errors and other semantic errors use
formatCompilerError()which doesn't populateContext(source lines). Reading the source file to extract the relevant lines would improve these messages:Implementation Guide
Files to Modify
pkg/console/console.goHintfield rendering inFormatError()after context blockpkg/workflow/compiler_error_formatter.gocausewhenmessage == cause.Error()pkg/workflow/compiler.goformatCompilerErrorpkg/parser/yaml_error.gopkg/parser/schema_errors.goSuccess Metrics
file:line:colmatches actual error line (not1:1)Hintfield is rendered when setReferences:
Generated by Daily Syntax Error Quality Check workflow
Next check: Runs daily