🔍 Duplicate Code Pattern: Duplicated addDetail() calls in formatErrorContext
Part of duplicate code analysis: #6781
Summary
The formatErrorContext function in internal/config/validation_schema.go contains identical addDetail() call pairs duplicated across two separate code blocks: a keyword-based switch statement (the primary path) and a series of message-based if strings.Contains(...) checks (the fallback path). Both blocks call addDetail() with the exact same key and message strings for 7 distinct error categories.
Duplication Details
Pattern: Identical addDetail() calls in keyword-switch and message-fallback blocks
- Severity: Medium
- Occurrences: 7 duplicated pairs (14 total
addDetail() calls for 7 keywords)
- Locations:
internal/config/validation_schema.go (lines 497–526) — keyword-based switch block
internal/config/validation_schema.go (lines 528–575) — message-based fallback if block
- Code Sample:
// PRIMARY PATH (switch on keyword, lines 497-526)
switch keyword {
case "additionalProperties":
addDetail("additionalProperties",
"Details: Configuration contains field(s) that are not defined in the schema",
" → Check for typos in field names or remove unsupported fields")
case "type":
addDetail("type",
"Details: Type mismatch - the value type doesn't match what's expected",
" → Verify the value is the correct type (string, number, boolean, object, array)")
// ... 5 more identical cases
}
// FALLBACK PATH (if strings.Contains, lines 528-575) — exact same addDetail calls
if strings.Contains(msg, "additionalProperties") || strings.Contains(msg, "additional property") {
addDetail("additionalProperties",
"Details: Configuration contains field(s) that are not defined in the schema",
" → Check for typos in field names or remove unsupported fields")
}
if strings.Contains(msg, "expected") && (strings.Contains(msg, "but got") || strings.Contains(msg, "type")) {
addDetail("type",
"Details: Type mismatch - the value type doesn't match what's expected",
" → Verify the value is the correct type (string, number, boolean, object, array)")
}
// ... 5 more identical blocks
Impact Analysis
- Maintainability: When error guidance text needs updating (e.g., improving a hint message), both the
switch case and the corresponding if block must be updated in sync. Missing one creates inconsistent behavior between primary and fallback paths.
- Bug Risk: Medium — the
added deduplication map prevents double-output at runtime, but a future developer could inadvertently change one block without the other, resulting in different messages on the primary vs. fallback path.
- Code Bloat: ~42 lines of duplicated code (30 in the switch + 12 key duplicated lines in the fallback)
Refactoring Recommendations
Option 1: Extract detailForKeyword helper (Recommended)
Extract the keyword→guidance mapping into a separate helper and call it from both the switch and fallback paths:
// detailForKeyword returns the (key, lines...) arguments for addDetail given a known keyword.
// Returns empty strings if the keyword is unknown.
func detailForKeyword(keyword string) (string, []string) {
switch keyword {
case "additionalProperties":
return "additionalProperties", []string{
"Details: Configuration contains field(s) that are not defined in the schema",
" → Check for typos in field names or remove unsupported fields",
}
case "type":
return "type", []string{
"Details: Type mismatch - the value type doesn't match what's expected",
" → Verify the value is the correct type (string, number, boolean, object, array)",
}
// ... other cases
}
return "", nil
}
// Then in formatErrorContext:
if k, lines := detailForKeyword(keyword); k != "" {
addDetail(k, lines...)
}
// Fallback: map message keywords to the same helper
for _, candidate := range []string{"additionalProperties", "type", "enum", "required", "pattern", "range", "oneOf"} {
if messageMatchesKeyword(msg, candidate) {
if k, lines := detailForKeyword(candidate); k != "" {
addDetail(k, lines...)
}
}
}
Option 2: Consolidate into a single lookup table
Define a []keywordRule slice with keyword, msgPatterns, and lines fields, then loop once over the rules applying both the switch and message-fallback logic without duplication.
Option 3: Evaluate necessity of fallback
Now that keywordFromLocation is the primary classification path, determine whether the message-based fallback if-blocks are still needed. If the keyword location reliably covers all cases, the fallback blocks can be removed entirely, eliminating the duplication.
Implementation Checklist
Parent Issue
See parent analysis report: #6781
Related to #6781
Generated by Duplicate Code Detector · sonnet46 1.5M · ◷
🔍 Duplicate Code Pattern: Duplicated
addDetail()calls informatErrorContextPart of duplicate code analysis: #6781
Summary
The
formatErrorContextfunction ininternal/config/validation_schema.gocontains identicaladdDetail()call pairs duplicated across two separate code blocks: a keyword-basedswitchstatement (the primary path) and a series of message-basedif strings.Contains(...)checks (the fallback path). Both blocks calladdDetail()with the exact same key and message strings for 7 distinct error categories.Duplication Details
Pattern: Identical
addDetail()calls in keyword-switch and message-fallback blocksaddDetail()calls for 7 keywords)internal/config/validation_schema.go(lines 497–526) — keyword-basedswitchblockinternal/config/validation_schema.go(lines 528–575) — message-based fallbackifblockImpact Analysis
switchcase and the correspondingifblock must be updated in sync. Missing one creates inconsistent behavior between primary and fallback paths.addeddeduplication map prevents double-output at runtime, but a future developer could inadvertently change one block without the other, resulting in different messages on the primary vs. fallback path.Refactoring Recommendations
Option 1: Extract
detailForKeywordhelper (Recommended)Extract the keyword→guidance mapping into a separate helper and call it from both the switch and fallback paths:
Option 2: Consolidate into a single lookup table
Define a
[]keywordRuleslice withkeyword,msgPatterns, andlinesfields, then loop once over the rules applying both the switch and message-fallback logic without duplication.Option 3: Evaluate necessity of fallback
Now that
keywordFromLocationis the primary classification path, determine whether the message-based fallbackif-blocks are still needed. If the keyword location reliably covers all cases, the fallback blocks can be removed entirely, eliminating the duplication.Implementation Checklist
detailForKeywordhelper (or equivalent) to centralize guidance stringsformatErrorContextto call the helper from both pathsvalidation_schema_error_format_test.gostill passParent Issue
See parent analysis report: #6781
Related to #6781