Skip to content

Commit edc7127

Browse files
committed
colexecerror: check for internal errors before examining stack
Informs: cockroachdb#123235 Release note: None
1 parent 22e9c29 commit edc7127

File tree

2 files changed

+58
-9
lines changed

2 files changed

+58
-9
lines changed

pkg/sql/colexec/colexecwindow/min_max_queue.go

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,6 @@ func (q *minMaxQueue) get(pos int) uint32 {
6363
}
6464

6565
// getFirst returns the element at the start of the minMaxQueue.
66-
// gcassert:inline
6766
func (q *minMaxQueue) getFirst() uint32 {
6867
if q.empty {
6968
colexecerror.InternalError(errors.AssertionFailedf("getting first from empty minMaxQueue"))

pkg/sql/colexecerror/error.go

Lines changed: 58 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -42,17 +42,42 @@ func CatchVectorizedRuntimeError(operation func()) (retErr error) {
4242
// StorageError was caused by something below SQL, and represents an error
4343
// that we'd simply like to propagate along.
4444
var se *StorageError
45-
// notInternalError is an error that will be returned to the client
46-
// without a stacktrace, sentry report, or "internal error" designation.
45+
// notInternalError is an error from the vectorized engine that we'd
46+
// simply like to propagate along.
4747
var nie *notInternalError
48-
if errors.As(err, &se) || errors.As(err, &nie) {
48+
// internalError is an error from the vectorized engine that might need to
49+
// be returned to the client with a stacktrace, sentry report, and
50+
// "internal error" designation.
51+
var ie *internalError
52+
passthrough := errors.As(err, &se) || errors.As(err, &nie)
53+
if errors.As(err, &ie) {
54+
// Unwrap so that internalError doesn't show up in sentry reports.
55+
retErr = ie.Unwrap()
56+
// If the internal error doesn't already have an error code, mark it as
57+
// an assertion error so that we generate a sentry report. (We don't do
58+
// this for StorageError, notInternalError, or context.Canceled to avoid
59+
// creating unnecessary sentry reports.)
60+
if !passthrough && !errors.Is(retErr, context.Canceled) {
61+
if code := pgerror.GetPGCode(retErr); code == pgcode.Uncategorized {
62+
retErr = errors.NewAssertionErrorWithWrappedErrf(
63+
retErr, "unexpected error from the vectorized engine",
64+
)
65+
}
66+
}
67+
return
68+
}
69+
if passthrough {
4970
retErr = err
5071
return
5172
}
5273
}
5374

54-
// Find where the panic came from and only proceed if it is related to the
55-
// vectorized engine.
75+
// For other types of errors, we need to check where the panic came from. We
76+
// only want to recover from panics that originated within the vectorized
77+
// engine. We treat a panic from lower in the stack as unrecoverable.
78+
79+
// Find where the panic came from and only proceed if it
80+
// is related to the vectorized engine.
5681
stackTrace := string(debug.Stack())
5782
scanner := bufio.NewScanner(strings.NewReader(stackTrace))
5883
panicLineFound := false
@@ -193,16 +218,41 @@ func decodeNotInternalError(
193218
return newNotInternalError(cause)
194219
}
195220

221+
// internalError is an error that occurs because the vectorized engine is in an
222+
// unexpected state. Usually it wraps an assertion error.
223+
type internalError struct {
224+
cause error
225+
}
226+
227+
func newInternalError(err error) *internalError {
228+
return &internalError{cause: err}
229+
}
230+
231+
var (
232+
_ errors.Wrapper = &internalError{}
233+
)
234+
235+
func (e *internalError) Error() string { return e.cause.Error() }
236+
func (e *internalError) Cause() error { return e.cause }
237+
func (e *internalError) Unwrap() error { return e.Cause() }
238+
239+
func decodeInternalError(
240+
_ context.Context, cause error, _ string, _ []string, _ proto.Message,
241+
) error {
242+
return newInternalError(cause)
243+
}
244+
196245
func init() {
197246
errors.RegisterWrapperDecoder(errors.GetTypeKey((*notInternalError)(nil)), decodeNotInternalError)
247+
errors.RegisterWrapperDecoder(errors.GetTypeKey((*internalError)(nil)), decodeInternalError)
198248
}
199249

200-
// InternalError simply panics with the provided object. It will always be
201-
// caught and returned as internal error to the client with the corresponding
250+
// InternalError panics with the error wrapped by internalError. It will always
251+
// be caught and returned as internal error to the client with the corresponding
202252
// stack trace. This method should be called to propagate errors that resulted
203253
// in the vectorized engine being in an *unexpected* state.
204254
func InternalError(err error) {
205-
panic(err)
255+
panic(newInternalError(err))
206256
}
207257

208258
// ExpectedError panics with the error that is wrapped by

0 commit comments

Comments
 (0)