Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 39 additions & 0 deletions decode_hooks_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -682,6 +682,45 @@ func TestStringToTimeLocationHookFunc(t *testing.T) {
suite.Run(t)
}

// Regression test: a platform without a readable zoneinfo database surfaces a raw
// syscall error from time.LoadLocation (e.g. "operation not permitted" on sandboxed
// darwin, ENOSYS on some containers) instead of "unknown time zone" — the hook must
// normalize either into a stable error message.
func TestStringToTimeLocationHookFunc_NormalizesRawLoadLocationErrors(t *testing.T) {
t.Setenv("ZONEINFO", "")

f := StringToTimeLocationHookFunc()
_, err := DecodeHookExec(f, reflect.ValueOf("Mars/Olympus_Mons"), reflect.ValueOf(time.Local))
if err == nil {
t.Fatal("expected an error for an unknown time zone")
}

if !strings.Contains(err.Error(), "invalid time zone format") {
t.Fatalf("expected a normalized time zone error, got: %v", err)
}
}

func TestStringToTimeLocationHookFunc_DirectLoadLocationErrorIsWrapped(t *testing.T) {
raw := errors.New("operation not permitted")

wrapped := wrapTimeParseLocationError(raw)
if wrapped == nil {
t.Fatal("expected a wrapped error, got nil")
}
if !errors.Is(wrapped, raw) {
t.Fatalf("expected the raw error to be wrapped, got: %v", wrapped)
}
if got := wrapped.Error(); got != "invalid time zone format: operation not permitted" {
t.Fatalf("unexpected wrapped message: %q", got)
}
}

func TestStringToTimeLocationHookFunc_NilErrorPassesThrough(t *testing.T) {
if err := wrapTimeParseLocationError(nil); err != nil {
t.Fatalf("expected nil, got %v", err)
}
}

func TestStringToURLHookFunc(t *testing.T) {
httpURL, _ := url.Parse("http://example.com")
httpsURL, _ := url.Parse("https://example.com")
Expand Down
9 changes: 4 additions & 5 deletions errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -231,14 +231,13 @@ func wrapTimeParseDurationError(err error) error {
return err
}

// Always wrap so the message does not leak platform-dependent syscall text:
// LoadLocation surfaces the raw firstErr (e.g. "operation not permitted" on a
// sandboxed darwin host), instead of "unknown time zone <name>".
func wrapTimeParseLocationError(err error) error {
if err == nil {
return nil
}
errMsg := err.Error()
if strings.Contains(errMsg, "unknown time zone") || strings.HasPrefix(errMsg, "time: unknown format") {
return fmt.Errorf("invalid time zone format: %w", err)
}

return err
return fmt.Errorf("invalid time zone format: %w", err)
}