diff --git a/internal/config/config_core.go b/internal/config/config_core.go index deef8aaa..9f75dbb7 100644 --- a/internal/config/config_core.go +++ b/internal/config/config_core.go @@ -11,7 +11,7 @@ // # Design Patterns // // Streaming Decoder: Uses toml.NewDecoder() for memory efficiency with large configs -// Error Reporting: Extracts line/column from ParseError for precise error messages +// Error Reporting: Wraps ParseError with %w to preserve structured type and surface full source context // Unknown Fields: Uses MetaData.Undecoded() for typo warnings (not hard errors) // Validation: Multi-layer approach (parse → schema → field-level → variable expansion) // @@ -212,19 +212,11 @@ func LoadFromFile(path string) (*Config, error) { decoder := toml.NewDecoder(file) md, err := decoder.Decode(&cfg) if err != nil { - // Extract position information from ParseError for better error messages - // Note: We use Position.Line, Position.Col, and Message separately to provide - // a consistent, precise error format. perr.Error() includes line info but not - // column, so we construct our own message with both for better UX. - // Try pointer type first (for compatibility) - if perr, ok := err.(*toml.ParseError); ok { - return nil, fmt.Errorf("failed to parse TOML at line %d, column %d: %s", - perr.Position.Line, perr.Position.Col, perr.Message) - } - // Try value type (used by toml.Decode) + // toml.Decode returns ParseError as a value type. Wrap with %w to preserve + // the structured error for callers while surfacing the full source context + // (line snippet + column pointer) via ParseError.Error(). if perr, ok := err.(toml.ParseError); ok { - return nil, fmt.Errorf("failed to parse TOML at line %d, column %d: %s", - perr.Position.Line, perr.Position.Col, perr.Message) + return nil, fmt.Errorf("failed to parse TOML: %w", perr) } return nil, fmt.Errorf("failed to parse TOML: %w", err) }