Repository navigation
Conversation
JeremyLoy
added this pull request to stack #21
October 12, 2026 05:15
fix: crashes on pointer/unexported fields, slice appends, error accumulation
Any field whose pointer implements encoding.TextUnmarshaler is parsed with UnmarshalText, as a single value. This adds time.Time, netip.Addr, netip.Prefix, net.IP, slog.Level, big.Int and user-defined types without special cases, including slices of them. - Such struct types (time.Time, netip.Addr) are no longer descended into as sub-configs. - Such slice types (net.IP is a []byte) are no longer split on spaces. - UnmarshalText errors are reported as ErrInvalidValue because they may contain the configured value. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NUxivLjodSESTkzRtdQ4CP
JeremyLoy
force-pushed
the
feat/text-unmarshaler
branch
from
October 12, 2026 05:39
76f4e10 to
be168e6
Compare
* 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>
* feat: return a typed *config.Error with per-field causes 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 * chore: require Go 1.27 and modernize (#16) * 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> --------- Co-authored-by: Claude <noreply@anthropic.com>
# Conflicts: # decode.go # util.go
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Stack 5/7. Base: #17.
Any field whose pointer implements
encoding.TextUnmarshaleris now parsed withUnmarshalTextas a single value. That coverstime.Time,netip.Addr/Prefix,net.IP,slog.Level,big.Intand users' own types, plus slices of any of them, with no special cases.Details
time.Time,netip.Addr) are now treated as single values instead of being descended into as sub-configs.net.IPis a[]byte) are no longer split on spaces.UnmarshalTexterrors are reported asErrInvalidValue, because they often include the input.Edge case: a nested config struct that embeds a
TextUnmarshaler(e.g.struct{ time.Time; Port int }) picks upUnmarshalTextthrough embedding and is now treated as a single value. I expect this to be rare. Say if you want an opt-out.Verification
Test_textUnmarshalercoversnetip.Addr,[]netip.Addr,net.IP,slog.Level, nested and top-leveltime.Time, and a custom type that returns an error. It fails without this change. AddedExample_textUnmarshaler. The full suite plusvetandstaticcheckpass on go1.26 and go1.27.🤖 Generated with Claude Code
https://claude.ai/code/session_01NUxivLjodSESTkzRtdQ4CP
Generated by Claude Code