error-messages について
gh-aw の検証エラーを書く開発者向けのスタイルガイドです。問題点、期待される形式、具体的な修正例を示す構成と、例やテストの指針を説明します。
主な機能
- 01問題と修正を軸にエラーを構成
- 02実行可能な表現を推奨
- 03検証エラーと操作エラーを区別
- 04YAML とコードの例を掲載
- 05改善したメッセージのテストを推奨
活用シーン
- 01gh-aw の検証メッセージ作成
- 02曖昧な設定エラーの改善
- 03形式や型のエラーへの例の追加
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ github/ gh-aw --skill error-messagesインストール後、Claude Code で/error-messagesを入力して読み込まれたか確認します。
同梱ファイルssl.json
詳細
エラーメッセージのスタイルガイド
gh-aw の検証エラーには、次の形式を使用してください。メッセージは明確で、対処方法がわかり、例を示すものにしてください。
エラーメッセージのテンプレート
[what's wrong]. [what's expected]. [example of correct usage]
各エラーメッセージで、次の3つの質問に答えてください。
- 何が問題ですか? - 検証エラーを明確に示します
- 何が期待されていますか? - 有効な形式や値を説明します
- どうすれば修正できますか? - 正しい使い方の具体例を示します
建設的な表現
否定的な表現だけを単独で使わないでください。期待される動作と具体的な修正方法を合わせて示します。
| 否定的な表現のみ | 建設的な表現 |
|---|---|
invalid | expected + 有効な形式/選択肢 |
cannot | requires + 前提条件 |
must | should + 例 |
failed | 操作の状況 + 復旧手順 |
❌ 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
NewValidationError と fmt.Errorf の使い分け
*_validation.goのロジックでは、NewValidationError(field, value, reason, suggestion)を使用します。fieldには正確な設定パスを指定しますreasonには失敗した理由を指定しますsuggestionには、例を含む実行可能な修正方法を指定します
%wを使って下位レベルのエラーをコンテキストとともに伝播する、操作上のエラーやラップするエラーにはfmt.Errorfを使用します。- 復旧方法を追加しない限り、
fmt.Errorf("failed to X: %w", err)のような一般的なラッパーは避けてください。
提案文のチェックリスト
各 suggestion では、次のことを行ってください。
- 変更する内容を説明する
- 最小限の有効な YAML/コード例を含める
- 曖昧さが生じる可能性がある場合は ✓/✗ マーカーを使う
例:
Use one supported engine.
✓ Example:
engine: copilot
✗ Avoid:
engine: unknown
YAML の例に関するガイドライン
- 最小限の有効な YAML の例を使う
- 実際のフロントマターのフィールド名を使う
- YAML で必要な場合にのみ引用符を付ける
- 2スペースのインデントを推奨します
良い例
次の例はテンプレートに従い、具体的な対処方法を示しています。
時間差分の検証(time_delta.go より)
return nil, fmt.Errorf("invalid time delta format: +%s. Expected format like +25h, +3d, +1w, +1mo, +1d12h30m", deltaStr)
✅ 良い理由:
- 無効な入力を明確に特定しています
- 有効な形式の例を複数示しています
- 組み合わせ形式(+1d12h30m)を示しています
例を含む型の検証
return "", fmt.Errorf("manual-approval value must be a string, got %T. Example: manual-approval: \"production\"", val)
✅ 良い理由:
- 実際に受け取った型(%T)を示しています
- 具体的な YAML の例を提示しています
- 引用符を使った適切な YAML 構文になっています
選択肢を含む列挙型の検証
return fmt.Errorf("invalid engine: %s. Valid engines are: copilot, claude, codex, custom. Example: engine: copilot", engineID)
✅ 良い理由:
- 有効な選択肢をすべて示しています
- 最も簡単な例を提示しています
- 一貫した書式を使っています
MCP の設定
return fmt.Errorf("tool '%s' mcp configuration must specify either 'command' or 'container'. Example:\ntools:\n %s:\n command: \"npx @my/tool\"", toolName, toolName)
✅ 良い理由:
- 相互排他性を説明しています
- 現実的なツール名を示しています
- 複数行の YAML の例を整形して示しています
悪い例
次の例は明確さや具体的な対処方法に欠けています。
曖昧すぎる
return fmt.Errorf("invalid format")
❌ 問題点:
- どの形式が無効なのかを指定していません
- 期待される形式を説明していません
- 例がありません
例がない
return fmt.Errorf("manual-approval value must be a string")
❌ 問題点:
- 要件を示していますが、例がありません
- 適切な YAML 構文がわかりません
- 受け取った型をもっと明確に示せます
情報が不完全
return fmt.Errorf("invalid engine: %s", engineID)
❌ 問題点:
- 有効な選択肢を列挙していません
- エラーの修正方法を案内していません
- ユーザーがドキュメントを探す必要があります
例を含める場合
次の場合は必ず例を含めてください。
-
形式/構文エラー - 正しい構文を示します
fmt.Errorf("invalid date format. Expected: YYYY-MM-DD HH:MM:SS. Example: 2024-01-15 14:30:00") -
列挙型/選択肢フィールド - 有効な選択肢をすべて列挙します
fmt.Errorf("invalid permission level: %s. Valid levels: read, write, none. Example: permissions:\n contents: read", level) -
型の不一致 - 期待される型と例を示します
fmt.Errorf("timeout-minutes must be an integer, got %T. Example: timeout-minutes: 10", value) -
複雑な設定 - 完全で有効な例を示します
fmt.Errorf("invalid MCP server config. Example:\nmcp-servers:\n my-server:\n command: \"node\"\n args: [\"server.js\"]")
例を省略してもよい場合
次の場合は、例を省略できます。
-
ラップされたエラーによるエラー - 別のエラーをコンテキストとともにラップする場合
return fmt.Errorf("failed to parse configuration: %w", err) -
明確なコンテキストがあり、エラーの内容が自明な場合
return fmt.Errorf("duplicate unit '%s' in time delta: +%s", unit, deltaStr) -
エラーが具体的なドキュメントを参照している場合
return fmt.Errorf("unsupported feature. See https://docs.example.com/features")
書式設定のガイドライン
動的な内容には型を表す動詞を使う
%s- 文字列%d- 整数%T- 値の型%v- 一般的な値%w- ラップされたエラー
複数行の例
複数行にわたる YAML 設定の例には、次の形式を使います。
fmt.Errorf("invalid config. Example:\ntools:\n github:\n mode: \"remote\"")
例での引用
例では適切な YAML 構文を使用してください:
// Good - shows quotes when needed
fmt.Errorf("Example: name: \"my-workflow\"")
// Good - shows no quotes for simple values
fmt.Errorf("Example: timeout-minutes: 10")
用語の一貫性
YAML と同じフィールド名を使用してください:
// Good - matches YAML field name
fmt.Errorf("timeout-minutes must be positive")
// Bad - uses different name
fmt.Errorf("timeout must be positive")
エラーメッセージのテスト
改善されたすべてのエラーメッセージには、対応するテストが必要です:
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:")
}
移行戦略
既存のエラーメッセージを改善する場合:
- エラーを特定する - 明確さに欠ける検証エラーを見つけます
- コンテキストを分析する - 何が検証されているのかを理解します
- テンプレートを適用する - 何が問題か + 期待される内容 + 例を追加します
- テストを追加する - エラーメッセージの内容を検証します
- コメントを更新する - 検証ロジックを文書化します
カテゴリ別の例
フォーマットの検証
// 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)
型の検証
// 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)
選択肢/Enum の検証
// 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)
設定の検証
// 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\"")
参考資料
- 参考にすべき優れた例:
pkg/workflow/time_delta.go - パターンのヒント: Go 標準ライブラリのエラーメッセージ
- テストの例:
pkg/workflow/*_test.go
ツール
エラーメッセージを書く際には、以下を考慮してください:
- ユーザーの視点 (修正するために何が必要か?)
- コンテキスト (ワークフローのどこでエラーが発生したか?)
- ドキュメント (特定のドキュメントを参照すべきか?)
- 複雑さ (複数行の例が必要か?)