Documentation
¶
Overview ¶
Package uerr is ursus's error type.
Error message quality is a feature, not a courtesy. A dataframe library is used interactively; the difference between
unknown column
and
ursus: select: unknown column "reveune" did you mean: "revenue"? available: id, ts, revenue, region, units
is the difference between a library people enjoy and one they tolerate. Every error that names a column MUST list the available columns and offer near matches; the helpers here make that the path of least resistance.
Index ¶
- Variables
- func Annotate(err error, op, node string) error
- func Catch(errp *error, op string)
- func Guard[T any](op string, fn func() (T, error)) (v T, err error)
- func GuardErr(op string, fn func() error) (err error)
- func NearMatches(want string, candidates []string, n int) []string
- func Raise(e *Error)
- type Error
- func Attributed(v any, kind Kind, op, format string, args ...any) *Error
- func DuplicateColumn(op, name string, firstAt, secondAt int) *Error
- func FromPanic(v any, op string) *Error
- func Internalf(format string, args ...any) *Error
- func New(kind Kind, op, format string, args ...any) *Error
- func UnknownColumn(op, name string, available []string) *Error
- func Wrap(err error, kind Kind, op, format string, args ...any) *Error
- type Kind
- type PanicError
Constants ¶
This section is empty.
Variables ¶
var ( ErrInternal error = &kindSentinel{KindInternal} ErrSchema error = &kindSentinel{KindSchema} ErrType error = &kindSentinel{KindType} ErrValue error = &kindSentinel{KindValue} ErrUnsupported error = &kindSentinel{KindUnsupported} ErrIO error = &kindSentinel{KindIO} ErrResource error = &kindSentinel{KindResource} )
Sentinels for errors.Is. Use as: errors.Is(err, uerr.ErrSchema).
Functions ¶
func Annotate ¶
Annotate applies WithOp/WithNode to err if it is an *Error, and otherwise leaves it alone. Plan nodes call this as errors propagate outward.
func Catch ¶ added in v0.3.0
Catch recovers a panic into *errp, as FromPanic describes. It must be deferred DIRECTLY — `defer uerr.Catch(&err, op)` — because recover only stops a panic when called by the deferred function itself.
Without a panic it leaves *errp alone, so it costs nothing on the path that returns normally.
func NearMatches ¶
NearMatches returns up to n candidates that are plausible typos of want, best first.
Two signals, because they catch different mistakes:
- Edit distance catches transpositions and single-character slips ("reveune" → "revenue"), which are what people actually type.
- Case-insensitive equality and SEPARATOR SQUASHING catch the other common failure, which is not a typo at all but a naming-convention mismatch ("userid" → "user_id", "TS" → "ts"). This used to say "prefix containment", which is not implemented and never was; squash() strips _ - . and space.
The distance budget scales with length: one edit for short names, up to three for long ones. A fixed budget either floods short-name suggestions or misses long-name typos.
func Raise ¶ added in v0.3.0
func Raise(e *Error)
Raise panics with e on purpose, for a constructor whose signature has no error to return: a String column past what its 32-bit offsets hold, say. FromPanic and Attributed return e itself, whatever its kind, where an *Error panicked any other way is taken for a bug.
Every operator boundary recovers a panic (step 72), so a Raise surfaces as e from Collect and its siblings. One that reaches a caller's own goroutine — through a public constructor called directly — prints e's message.
Types ¶
type Error ¶
type Error struct {
Kind Kind
Op string // "select", "filter", "with_columns"
Msg string // the one-line statement of what is wrong
Node string // plan node attribution, e.g. "Project#3"; set by WithNode
Hints []string // one per line, indented under Msg
Err error // wrapped cause, if any
}
Error is ursus's error type.
Op is the user-facing operation ("select", "filter", "cast"), not the Go function name. Node is set by the plan layer as the error propagates outward, so a user learns *where* in their query the failure was — something a bare error string cannot express.
func Attributed ¶ added in v0.3.0
Attributed turns a value recovered from code ursus calls but did not write — a user's udf, or a decoder reading a file — into an error of that code's kind.
An internal *Error still passes through: raised by ursus, it is ursus's bug wherever it surfaced.
func DuplicateColumn ¶
DuplicateColumn reports a name collision, naming both positions.
func FromPanic ¶ added in v0.3.0
FromPanic turns a value recovered from ursus's own code into an internal error.
An internal *Error passes through unchanged: it is ursus's own assertion (Internalf, raised where a signature has no error to return), and it already says what it is. Anything else — a runtime error, a string, an *Error of another kind — is a bug in ursus too, and becomes KindInternal with the value as its cause.
func UnknownColumn ¶
UnknownColumn is the single most common error in a dataframe library, so it has a dedicated constructor that always produces the full diagnostic.
type Kind ¶
type Kind uint8
Kind classifies an error so callers can branch without string matching.
const ( // KindInternal is a bug in ursus. Users should never legitimately see one. KindInternal Kind = iota // KindSchema is an unknown, duplicate, or ambiguous column. KindSchema // KindType is a dtype mismatch: an operation not defined for the given types. KindType // KindValue is a bad literal, an out-of-range cast, an unparseable pattern. KindValue // KindUnsupported is a well-formed request ursus cannot yet serve. KindUnsupported // KindIO is a failure reading or writing a data source. KindIO // KindResource is a limit ursus refused to exceed rather than a request it // could not understand: the query is well-formed and would have worked with // more memory or more spill space. // // It is its own kind because it is the one class of failure where the right // response is to change a knob and retry, and a caller should be able to // detect that without matching on a message. KindResource )
func (Kind) String ¶
String names the kind, or reports the number for one that has no name.
The fallback used to be `default: return "internal"`, which is worse here than the identical hazard fixed for JoinKind in step 51 — because KindInternal is the ZERO VALUE, the default arm was legitimately reached for it and the omission read as deliberate. An eighth kind added without a table entry would have rendered as "internal", whose own doc says "a bug in ursus; users should never legitimately see one". A resource or IO failure mislabelled as an ursus bug is the wrong advice to give a user, and it is the failure mode ConcatMode.String's comment documents for eight enums; this is the ninth.
The `!= ""` half is the load-bearing one: the array is sized by kindCount, so a forgotten entry is the empty string rather than a missing index.
type PanicError ¶ added in v0.3.0
type PanicError struct {
Value any // what was passed to panic
Site string // the function and line that panicked, or "" if not found
Stack []byte // the goroutine's stack at the recover
// Callers are the functions from the panic site outward, the runtime's own left
// out. It is how a recover decides whose code panicked: a Parquet read that
// panicked inside arrow-go was reading a corrupt file, and one that panicked in
// ursus is ursus's bug.
Callers []string
}
PanicError is a recovered panic: the value, where it was raised, and the stack.
A panic is an error, never a dead process ¶
ursus runs a query's expressions on worker goroutines, and a panic in a worker goroutine can be recovered by no one else — not the caller, not a test, not the program that asked the question. Until step 72 one panic in one row killed the host process. Every place ursus runs code now recovers around the CALL, and turns what it recovers into an ordinary error through FromPanic or Attributed.
func (*PanicError) Error ¶ added in v0.3.0
func (p *PanicError) Error() string
func (*PanicError) Unwrap ¶ added in v0.3.0
func (p *PanicError) Unwrap() error
Unwrap exposes a panic value that is itself an error, so errors.As finds a runtime.Error — a nil dereference, an index out of range — through the result.
Never an ursus *Error. Its Kind would then answer errors.Is for a kind that is not the result's: data.MustValues panics with a KindType error, and a caller asking errors.Is(err, ErrType) of the internal error it became would get true.