vitessio/vitess · critical
uncaught panic: %v, vtgate: %v
Error message
uncaught panic: %v, vtgate: %v
What it means
VTGate recovered from an unrecovered panic inside a request-handling goroutine. The panic value is re-thrown to the caller as an error with the vtgate listening URL appended so the client knows which gate instance handled (and crashed on) the request. A 'Panic' counter is also incremented with code INTERNAL.
Source
Thrown at go/vt/vtgate/vtgate.go:1027
}
// log only if sql query present and able to successfully redact the PII.
logger.Infof("unsupported query: %q", piiSafeSQL)
}
return err
}
func formatError(err error) error {
if err == nil {
return nil
}
return err
}
// HandlePanic recovers from panics, and logs / increment counters
func (vtg *VTGate) HandlePanic(err *error) {
if x := recover(); x != nil {
log.Error(fmt.Sprintf("Uncaught panic:\n%v\n%s", x, tb.Stack(4)))
*err = fmt.Errorf("uncaught panic: %v, vtgate: %v", x, servenv.ListeningURL.String())
errorCounts.Add([]string{"Panic", "Unknown", "Unknown", vtrpcpb.Code_INTERNAL.String()}, 1)
}
}
func newVTGate(executor *Executor, resolver *Resolver, vsm *vstreamManager, tc *TxConn, gw *TabletGateway) *VTGate {
return &VTGate{
executor: executor,
resolver: resolver,
vsm: vsm,
txConn: tc,
gw: gw,
timings: timings,
rowsReturned: rowsReturned,
rowsAffected: rowsAffected,
queryTextCharsProcessed: queryTextCharsProcessed,
logExecute: logutil.NewThrottledLogger("Execute", 5*time.Second),
logPrepare: logutil.NewThrottledLogger("Prepare", 5*time.Second),View on GitHub (pinned to 01a25a7d17)
Solutions
- Read the full 'Uncaught panic:' stack trace in the vtgate log at the reported URL to identify the panicking function
- Check the panic value: nil-pointer on a nil session/plan usually indicates a client sending requests with unexpected fields
- Search Vitess issues for the panicking function; upgrade to a release containing the fix
- If reproducible, file a bug with the stack trace, query, and schema/vschema
- As mitigation, retry against a different vtgate instance since the panic is contained per-request
Example fix
// before: opaque INTERNAL error surfaced to client // after: capture root cause from logs and avoid trigger // log: Uncaught panic: runtime error: invalid memory address ... vtgate/exec.go:123 // action: upgrade Vitess to version fixing exec.go:123, or stop sending the offending query shape
Defensive patterns
Strategy: try-catch
Try / catch
res, err := vtgateConn.Execute(ctx, target, sql, bindVars)
if err != nil && strings.Contains(err.Error(), "uncaught panic") {
// request killed vtgate internals; capture err (contains vtgate URL),
// retry on another vtgate or report with the stack trace from server logs
return nil, fmt.Errorf("vtgate panicked (%w); see server logs at reported URL", err)
} Prevention
- Keep vtgate on the latest patch release — panics are fixed as INTERNAL bugs
- Monitor the errorCounts 'Panic' counter and alert on any increase
- Correlate the panic's vtgate URL in the error with server-side stack traces
- Avoid untested query shapes/features against production vtgate until validated in staging
When it happens
Trigger: Any panic during query execution in vtgate (nil pointer in executor, malformed internal state, bug in a plugin/resolver) that is caught by the deferred HandlePanic(err) in the RPC handler wrappers.
Common situations: Hitting an untested code path in a query plan, a bug after a Vitess upgrade, corrupt session state, or concurrency bugs surfacing as nil dereferences during load.
Related errors
AI-assisted analysis of vitessio/vitess@01a25a7d17 (2026-09-01).
Data as JSON: /api/errors/04fd68f75b01c214.
Report an issue: GitHub.