Skip to content

feat: return a typed *config.Error with per-field causes - #17

Merged
JeremyLoy merged 4 commits into
modernize/go1.26from
feat/typed-errors
Oct 12, 2026
Merged

JeremyLoy merged 4 commits into
modernize/go1.26from
feat/typed-errors

Conversation

@JeremyLoy

Copy link
Copy Markdown
Owner

Stack 4/7. Base: #16.

To and Sub now return a *config.Error instead of a plain fmt.Errorf string. Error() produces exactly the same text as before, so existing output and string comparisons keep working.

API

type FieldError struct {
	Key string // "port", "sub__hosts[1]", "file[dev.config]"
	Err error  // cause; never contains the configured value
}
type Error struct{ Errors []*FieldError } // sorted by Key
func (*Error) Unwrap() []error

var ErrUnsupportedType, ErrInvalidValue error

Callers can now check what went wrong:

if cfgErr, ok := errors.AsType[*config.Error](err); ok { ... }
errors.Is(err, fs.ErrNotExist)   // a file is missing
errors.Is(err, strconv.ErrRange) // e.g. PORT=128 for an int8 field

Secrets are still kept out of errors

The library previously reported only a true/false result for each field so that configured values never ended up in logs. The new causes keep that guarantee:

  • *strconv.NumError is reduced to its Err (ErrSyntax or ErrRange).
  • Other parse failures become ErrInvalidValue.
  • Unsupported field types become ErrUnsupportedType.

Test_typedErrors checks that a value like SECRET=hunter2 doesn't appear in any error.

Verification

gofmt, vet, staticcheck and go test -race pass on go1.26 and go1.27. Example_errorInspection is added.

🤖 Generated with Claude Code

https://claude.ai/code/session_01NUxivLjodSESTkzRtdQ4CP


Generated by Claude Code

@JeremyLoy
JeremyLoy added this pull request to stack #21 October 12, 2026 05:15
JeremyLoy and others added 2 commits October 12, 2026 01:27
fix: crashes on pointer/unexported fields, slice appends, error accumulation
To and Sub now return *config.Error, which lists a *FieldError per failed
field or source, sorted by key. Error() is unchanged, so existing output and
string comparisons keep working.

- Error.Unwrap() []error and FieldError.Unwrap() expose causes to errors.Is
  and errors.AsType: fs.ErrNotExist / *fs.PathError for files,
  strconv.ErrSyntax / strconv.ErrRange for numbers and bools,
  ErrUnsupportedType for fields that cannot be configured, and
  ErrInvalidValue otherwise.
- Causes are sanitized so they never contain the configured value, keeping
  the existing guarantee that errors are safe to log.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NUxivLjodSESTkzRtdQ4CP
JeremyLoy and others added 2 commits October 12, 2026 01:41
* chore: require Go 1.26 and modernize

Go supports the two most recent releases (1.26 and 1.27), so raise the
go directive from 1.16 to 1.26.

- go fix: interface{} -> any, reflect.Ptr -> reflect.Pointer, maps.Copy,
  range-over-int, drop per-iteration `tt := tt` copies (1.22 semantics)
- strings.Cut in stringsToMap (resolves the 1.18 TODO)
- slices.Sort instead of sort.Strings
- reflect.TypeFor for the time.Duration and *url.URL checks instead of
  comparing PkgPath/Name strings
- reflect.Value.Fields iterator and StructField.IsExported in mapKeysToFields
- new(expr) replaces the func() interface{} { v := x; return &v }() test helpers
- t.Setenv / t.TempDir in Test_Api, which no longer clears the whole
  environment for later tests

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NUxivLjodSESTkzRtdQ4CP

* chore: require Go 1.27

Raise the go directive to 1.27.0 so generic methods (Go 1.27) can be used.

CI: replace the oldstable/stable matrix with "minimum" (the version in
go.mod, via go-version-file) and "stable". With GOTOOLCHAIN=auto an
oldstable 1.26 job would silently download and test 1.27.0 instead, so CI
now sets GOTOOLCHAIN=local to always test the Go it installed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NUxivLjodSESTkzRtdQ4CP

---------

Co-authored-by: Claude <noreply@anthropic.com>
@JeremyLoy
JeremyLoy merged commit 2310c04 into master Oct 12, 2026
4 checks passed
An error occurred while trying to automatically change base from modernize/go1.26 to master October 12, 2026 05:49
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants