JuliusBrussee/caveman · error
catalog
Error message
catalog %s: %w
What it means
load wraps any DecodeAndValidate failure from a candidate catalog file with the 'catalog %s: %w' prefix so callers know which path failed validation. It is a wrapping error; the root cause (unknown fields, duplicates, bad prices, etc.) is chained inside. On final failure the loader returns an empty entry list rather than partially trusted data.
Solutions
- Read the wrapped cause after 'catalog <path>:' — it names the exact rule that failed.
- Fix the offending entry in the YAML at that path per the cause (required fields, currency, prices, timestamps).
- Regenerate the catalog from the canonical source rather than hand-editing if available.
- Run DecodeAndValidate or the test suite on the file before deploying.
Defensive patterns
Strategy: try-catch
Validate before calling
if _, err := catalog.DecodeAndValidate(raw); err != nil {
log.Printf("catalog %s invalid: %v", path, err)
} Try / catch
entries, err := load(path)
if err != nil {
var wrapped *fmt.wrapError
if errors.As(err, &wrapped) {
log.Printf("root cause for %s: %v", path, wrapped.Unwrap())
}
return fallbackEntries()
} Prevention
- Always unwrap past the 'catalog <path>:' prefix to see the real cause
- Validate catalogs in CI before deploy
- Regenerate catalogs from a generator instead of hand edits
- Never deploy when load returns the empty-entries fallback silently
When it happens
Trigger: Calling load (and transitively loadCurrentCatalog / snapshotDrift) with a catalog YAML file that fails DecodeAndValidate for any reason — the path-specific wrapper is applied to the underlying error.
Common situations: A hand-edited or tool-generated catalog YAML with a typo in a field, a duplicate provider/model/region row, or an invalid URL/timestamp; pointing the loader at a stale schema file after a format version change.
Understand the failure class
Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.
Related errors
- : currency must be USD
- : must be a safe non-empty identifier
- : catalog must be a non-empty list
- catalog is empty
- duplicate provider/model/region row
AI-assisted analysis of JuliusBrussee/caveman@3ee70a1026 (2026-09-20).
Data as JSON: /api/errors/145b54ca791cccf1.
Report an issue: GitHub.
Appendix: source
Thrown at shared/platform/catalog/catalog.go:294
return verifiedAt
}
return "unknown"
}
func load() {
for _, path := range catalogCandidates() {
raw, err := os.ReadFile(path)
if err != nil {
loadErr = err
continue
}
decoded, err := DecodeAndValidate(raw)
if err == nil {
entries = decoded
loadErr = nil
return
}
loadErr = fmt.Errorf("catalog %s: %w", path, err)
}
entries = []Entry{}
}
// DecodeAndValidate strictly parses a catalog. Unknown YAML fields, duplicate
// provider/model/region rows, invalid URLs/timestamps, and unsafe prices reject
// the entire file; runtime must never load a plausible partial catalog.
func DecodeAndValidate(raw []byte) ([]Entry, error) {
dec := yaml.NewDecoder(bytes.NewReader(raw))
dec.KnownFields(true)
var decoded []Entry
if err := dec.Decode(&decoded); err != nil {
return nil, err
}
var trailing any
if err := dec.Decode(&trailing); err != io.EOF {
if err == nil {
return nil, fmt.Errorf("multiple YAML documents are not allowed")View on GitHub (pinned to 3ee70a1026)