Keep %#v of every LLM adapter error free of the API key (MQ-03)
%#v prints struct field names, so a key that spells one (for example "body" on ProviderError) leaked even though Error() was redacted. - llm.ProviderError and llm.RateLimitedError gain GoString returning their already-redacted Error text. - Both adapters' transportFailure now holds its fully redacted text and gains GoString. - The redact backstop now wraps every non-nil error when a key is set, so the returned error and every unwrapped layer print through redactedError.GoString, never a raw struct such as fmt.wrapError. - redactedError.As also refuses a match whose %#v form holds the key. - Contract test in both adapters: field-name keys (body, status, text, RetryAfter, msg, err, key, kind) on HTTP 500 "down" and 429, checking %#v of the returned error, every unwrapped layer and errors.As results. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -58,6 +58,9 @@ func (e *RateLimitedError) Error() string {
|
||||
return fmt.Sprintf("%s: retry after %v", ErrRateLimited, e.RetryAfter)
|
||||
}
|
||||
|
||||
// GoString keeps %#v to the redacted Error text instead of the fields.
|
||||
func (e *RateLimitedError) GoString() string { return e.Error() }
|
||||
|
||||
// Is reports whether target is ErrRateLimited.
|
||||
func (e *RateLimitedError) Is(target error) bool { return target == ErrRateLimited }
|
||||
|
||||
@@ -128,5 +131,9 @@ func (e *ProviderError) Body() string { return e.body }
|
||||
|
||||
func (e *ProviderError) Error() string { return e.text }
|
||||
|
||||
// GoString keeps %#v to the redacted Error text instead of the fields,
|
||||
// whose names could spell the credential.
|
||||
func (e *ProviderError) GoString() string { return e.text }
|
||||
|
||||
// Is reports whether target is ErrProvider.
|
||||
func (e *ProviderError) Is(target error) bool { return target == ErrProvider }
|
||||
|
||||
Reference in New Issue
Block a user