mcpbeat Sign in

Error Messages Agent Skill

Write consistent, actionable validation error messages in gh-aw.

2.3k tokens
context cost
SKILL.md, read when the skill is used
2
files
plus reference files
0
copies elsewhere
how many repositories repackaged it
4 864
stars on the repo
on the repository, not the skill itself

Install

one command, takes just this skill from the repository
npx skills add https://github.com/github/gh-aw --skill error-messages

What comes with it

3 677 bytes besides the instruction
ssl.json

The instruction itself

31 sections, as written by the author

Error Message Style Guide

Use this format for gh-aw validation errors. Keep messages clear, actionable, and example-driven.

Error Message Template

[what's wrong]. [what's expected]. [example of correct usage]

Make each error message answer three questions:

  • What's wrong? - Clearly state the validation error
  • What's expected? - Explain the valid format or values
  • How to fix it? - Provide a concrete example of correct usage

Constructive Language

Avoid standalone negative wording. Pair it with expected behavior and a concrete fix.

| Avoid only-negative wording | Prefer constructive wording |

|---|---|

| invalid | expected + valid format/options |

| cannot | requires + precondition |

| must | should + example |

| failed | action context + recovery step |

❌ invalid repo format: %s

✅ invalid repo format '%s' — expected 'owner/repo' format (for example: 'github/gh-aw')

❌ not in a git repository

✅ not in a git repository — run 'git init' or 'cd' to a git repository

When to use NewValidationError vs fmt.Errorf

  • Use NewValidationError(field, value, reason, suggestion) in *_validation.go logic.
  • Use field for the exact config path
  • Use reason for what failed
  • Use suggestion for an actionable fix with an example
  • Use fmt.Errorf for operational/wrapping errors (%w) where you are propagating a lower-level failure with context.
  • Avoid generic wrappers like fmt.Errorf("failed to X: %w", err) unless you add recovery guidance.

Suggestion Text Checklist

Every suggestion should:

  • Explain what to change
  • Include a minimal valid YAML/code example
  • Use ✓/✗ markers when ambiguity is likely

Example:

Use one supported engine.
✓ Example:
engine: copilot

✗ Avoid:
engine: unknown

YAML Example Guidelines

  • Keep examples minimal and valid YAML
  • Use real frontmatter field names
  • Quote only when YAML requires it
  • Prefer 2-space indentation

Good Examples

These examples follow the template and provide actionable guidance:

Time Delta Validation (from time_delta.go)

return nil, fmt.Errorf("invalid time delta format: +%s. Expected format like +25h, +3d, +1w, +1mo, +1d12h30m", deltaStr)

✅ Why it's good:

  • Clearly identifies the invalid input
  • Lists multiple valid format examples
  • Shows combined formats (+1d12h30m)

Type Validation with Example

return "", fmt.Errorf("manual-approval value must be a string, got %T. Example: manual-approval: \"production\"", val)

✅ Why it's good:

  • Shows actual type received (%T)
  • Provides concrete YAML example
  • Uses proper YAML syntax with quotes

Enum Validation with Options

return fmt.Errorf("invalid engine: %s. Valid engines are: copilot, claude, codex, custom. Example: engine: copilot", engineID)

✅ Why it's good:

  • Lists all valid options
  • Provides simplest example
  • Uses consistent formatting

MCP Configuration

return fmt.Errorf("tool '%s' mcp configuration must specify either 'command' or 'container'. Example:\ntools:\n  %s:\n    command: \"npx @my/tool\"", toolName, toolName)

✅ Why it's good:

  • Explains mutual exclusivity
  • Shows realistic tool name
  • Formats multi-line YAML example

Bad Examples

These examples lack clarity or actionable guidance:

Too Vague

return fmt.Errorf("invalid format")

❌ Problems:

  • Doesn't specify what format is invalid
  • Doesn't explain expected format
  • No example provided

Missing Example

return fmt.Errorf("manual-approval value must be a string")

❌ Problems:

  • States requirement but no example
  • User doesn't know proper YAML syntax
  • Could be clearer about type received

Incomplete Information

return fmt.Errorf("invalid engine: %s", engineID)

❌ Problems:

  • Doesn't list valid options
  • No guidance on fixing the error
  • User must search documentation

When to Include Examples

Always include examples for:

  • Format/Syntax Errors - Show the correct syntax
   fmt.Errorf("invalid date format. Expected: YYYY-MM-DD HH:MM:SS. Example: 2024-01-15 14:30:00")
  • Enum/Choice Fields - List all valid options
   fmt.Errorf("invalid permission level: %s. Valid levels: read, write, none. Example: permissions:\n  contents: read", level)
  • Type Mismatches - Show expected type and example
   fmt.Errorf("timeout-minutes must be an integer, got %T. Example: timeout-minutes: 10", value)
  • Complex Configurations - Provide complete valid example
   fmt.Errorf("invalid MCP server config. Example:\nmcp-servers:\n  my-server:\n    command: \"node\"\n    args: [\"server.js\"]")

When Examples May Be Optional

Examples can be omitted when:

  • Error is from wrapped error - When wrapping another error with context
   return fmt.Errorf("failed to parse configuration: %w", err)
  • Error is self-explanatory with clear context
   return fmt.Errorf("duplicate unit '%s' in time delta: +%s", unit, deltaStr)
  • Error points to specific documentation
   return fmt.Errorf("unsupported feature. See https://docs.example.com/features")

Formatting Guidelines

Use Type Verbs for Dynamic Content

  • %s - strings
  • %d - integers
  • %T - type of value
  • %v - general value
  • %w - wrapped errors

Multi-line Examples

For YAML configuration examples spanning multiple lines:

fmt.Errorf("invalid config. Example:\ntools:\n  github:\n    mode: \"remote\"")

Quoting in Examples

Use proper YAML syntax in examples:

// Good - shows quotes when needed
fmt.Errorf("Example: name: \"my-workflow\"")

// Good - shows no quotes for simple values
fmt.Errorf("Example: timeout-minutes: 10")

Consistent Terminology

Use the same field names as in YAML:

// Good - matches YAML field name
fmt.Errorf("timeout-minutes must be positive")

// Bad - uses different name
fmt.Errorf("timeout must be positive")

Error Message Testing

All improved error messages should have corresponding tests:

func TestErrorMessageQuality(t *testing.T) {
    err := validateSomething(invalidInput)
    require.Error(t, err)
    
    // Error should explain what's wrong
    assert.Contains(t, err.Error(), "invalid")
    
    // Error should include expected format or values
    assert.Contains(t, err.Error(), "Expected")
    
    // Error should include example
    assert.Contains(t, err.Error(), "Example:")
}

Migration Strategy

When improving existing error messages:

  • Identify the error - Find validation error that lacks clarity
  • Analyze context - Understand what's being validated
  • Apply template - Add what's wrong + expected + example
  • Add tests - Verify error message content
  • Update comments - Document the validation logic

Examples by Category

Format Validation

// Time deltas
fmt.Errorf("invalid time delta format: +%s. Expected format like +25h, +3d, +1w, +1mo, +1d12h30m", input)

// Dates
fmt.Errorf("invalid date format: %s. Expected: YYYY-MM-DD or relative like -1w. Example: 2024-01-15 or -7d", input)

// URLs
fmt.Errorf("invalid URL format: %s. Expected: https:// URL. Example: https://api.example.com", input)

Type Validation

// Boolean expected
fmt.Errorf("read-only must be a boolean, got %T. Example: read-only: true", value)

// String expected
fmt.Errorf("workflow name must be a string, got %T. Example: name: \"my-workflow\"", value)

// Object expected
fmt.Errorf("permissions must be an object, got %T. Example: permissions:\n  contents: read", value)

Choice/Enum Validation

// Engine selection
fmt.Errorf("invalid engine: %s. Valid engines: copilot, claude, codex, custom. Example: engine: copilot", id)

// Permission levels
fmt.Errorf("invalid permission level: %s. Valid levels: read, write, none. Example: contents: read", level)

// Tool modes
fmt.Errorf("invalid mode: %s. Valid modes: local, remote. Example: mode: \"remote\"", mode)

Configuration Validation

// Missing required field
fmt.Errorf("tool '%s' missing required 'command' field. Example:\ntools:\n  %s:\n    command: \"node server.js\"", name, name)

// Mutually exclusive fields
fmt.Errorf("cannot specify both 'command' and 'container'. Choose one. Example: command: \"node server.js\"")

// Invalid combination
fmt.Errorf("http MCP servers cannot use 'container' field. Example:\ntools:\n  my-http:\n    type: http\n    url: \"https://api.example.com\"")

References

  • Excellent example to follow: pkg/workflow/time_delta.go
  • Pattern inspiration: Go standard library error messages
  • Testing examples: pkg/workflow/*_test.go

Tools

When writing error messages, consider:

  • The user's perspective (what do they need to fix it?)
  • The context (where in the workflow is the error?)
  • The documentation (should we reference specific docs?)
  • The complexity (is multi-line example needed?)

Other skills for the same job

different authors, same section of the catalogue
Executing Plans
by ZhanlinCui
×5

Use when you have a written implementation plan to execute in a separate session with review checkpoints

542 tokens
Protocolsio Integration
by christophacham
×4

Integration with protocols.io API for managing scientific protocols. This skill should be used when working with protocols.io to search, create, update, or publish protocols; manage protocol steps and materials; handle discussions and comments; organize workspaces; upload and manage files; or integrate protocols.io functionality into workflows. Applicable for protocol discovery, collaborative protocol development, experiment tracking, lab protocol management, and scientific documentation.

3.9k tokens
Tailored Resume Generator
by frostant
×4

Analyzes job descriptions and generates tailored resumes that highlight relevant experience, skills, and achievements to maximize interview chances

3.1k tokens
Expo Dev Client
by openai
vendor ×3

Build and distribute Expo development clients locally or via TestFlight

878 tokens
Anndata
by christophacham
×3

Data structure for annotated matrices in single-cell analysis. Use when working with .h5ad files or integrating with the scverse ecosystem. This is the data format skill—for analysis workflows use scanpy; for probabilistic models use scvi-tools; for population-scale queries use cellxgene-census.

2.8k tokens
Benchling Integration
by christophacham
×3

Benchling R&D platform integration. Access registry (DNA, proteins), inventory, ELN entries, workflows via API, build Benchling Apps, query Data Warehouse, for lab data management automation.

3.5k tokens
Biopython
by christophacham
×3

Comprehensive molecular biology toolkit. Use for sequence manipulation, file parsing (FASTA/GenBank/PDB), phylogenetics, and programmatic NCBI/PubMed access (Bio.Entrez). Best for batch processing, custom bioinformatics pipelines, BLAST automation. For quick lookups use gget; for multi-service integration use bioservices.

3.7k tokens
Cellxgene Census
by christophacham
×3

Query the CELLxGENE Census (61M+ cells) programmatically. Use when you need expression data across tissues, diseases, or cell types from the largest curated single-cell atlas. Best for population-scale queries, reference atlas comparisons. For analyzing your own data use scanpy or scvi-tools.

4.1k tokens

How to use it

Copy the folder

Take github/error-messages from the repository into ~/.claude/skills for personal use, or into .claude/skills inside a project.

Check the name does not clash

The agent identifies a skill by the name field in its header. Two skills with the same name cannot sit side by side — one of them will be ignored.

Install what it needs

The instructions reference npx. Without those the skill loads but fails at the first command.