clawdforge/clients/go/errors.go
Kayos 237e2f7c34 clients/go: apply audit findings — fmt + doc + test coverage (3c62613 → new)
- L1: gofmt fix on models.go:81
- L2: rewrite misleading RunFailure doc comment (didn't actually embed APIError)
- L3: tighten Client doc to warn against post-construction field mutation
- L4: errors.New for non-formatting Errorf calls
- L5: add TestUploadFile lifting coverage from 0% → 100% on UploadFile
- L7: add context cancellation mid-multipart test

Audit: memory/clawdforge-audits/go-3c62613.md
2026-04-28 23:08:46 -07:00

61 lines
1.9 KiB
Go

package clawdforge
import (
"errors"
"fmt"
)
// ErrAuth is the sentinel returned for 401/403 responses from clawdforge.
// Use errors.Is(err, ErrAuth) to detect auth failures.
var ErrAuth = errors.New("clawdforge: authentication failed")
// APIError carries a non-2xx response from clawdforge — status code plus
// the response body (truncated to a sane size). It is returned for any
// HTTP status >= 400 that isn't an auth failure.
type APIError struct {
StatusCode int
// Body is the raw response body (truncated). Useful for debugging.
Body string
// Message is a short human-readable summary derived from the body
// when the body is JSON of the form {"error": "..."} or {"detail": "..."}.
Message string
}
func (e *APIError) Error() string {
if e.Message != "" {
return fmt.Sprintf("clawdforge: HTTP %d: %s", e.StatusCode, e.Message)
}
return fmt.Sprintf("clawdforge: HTTP %d: %s", e.StatusCode, e.Body)
}
// TransportError wraps a low-level network/transport failure (DNS, connect
// refused, TLS, EOF, context cancellation, etc.). The wrapped error is
// available via errors.Unwrap.
type TransportError struct {
Op string
Err error
}
func (e *TransportError) Error() string {
return fmt.Sprintf("clawdforge: transport %s: %v", e.Op, e.Err)
}
func (e *TransportError) Unwrap() error { return e.Err }
// RunFailure represents a 502 response from /run — clawdforge accepted the
// request but `claude -p` failed (timeout, non-zero exit, etc.). The body
// fields mirror the server's failure shape.
//
// RunFailure has its own StatusCode field (always 502) and is distinct from
// APIError so callers can branch on errors.As(err, &rf).
type RunFailure struct {
StatusCode int
Err string `json:"error"`
Stderr string `json:"stderr"`
DurationMS int `json:"duration_ms"`
StopReason string `json:"stop_reason"`
}
func (e *RunFailure) Error() string {
return fmt.Sprintf("clawdforge: run failed (stop_reason=%s): %s", e.StopReason, e.Err)
}