wavetermdev/waveterm · critical
recErr.Error()
Error message
recErr.Error()
What it means
This is the plain-text 500 response emitted by WebFnWrap (pkg/web/web.go:397) when a wrapped HTTP handler panics and the route was registered without JsonErrors. PanicHandler recovers the panic and converts it to an error; http.Error then writes recErr.Error() with HTTP 500. It signals an unexpected bug inside the handler, not a client mistake.
Source
Thrown at pkg/web/web.go:397
Active bool `json:"active"`
Open bool `json:"open"`
}
func WebFnWrap(opts WebFnOpts, fn WebFnType) WebFnType {
return func(w http.ResponseWriter, r *http.Request) {
defer func() {
recErr := panichandler.PanicHandler("WebFnWrap", recover())
if recErr == nil {
return
}
if opts.JsonErrors {
jsonRtn := marshalReturnValue(nil, recErr)
w.Header().Set(ContentTypeHeaderKey, ContentTypeJson)
w.Header().Set(ContentLengthHeaderKey, fmt.Sprintf("%d", len(jsonRtn)))
w.WriteHeader(http.StatusOK)
w.Write(jsonRtn)
} else {
http.Error(w, recErr.Error(), http.StatusInternalServerError)
}
}()
if !opts.AllowCaching {
w.Header().Set(CacheControlHeaderKey, CacheControlHeaderNoCache)
}
w.Header().Set("Access-Control-Expose-Headers", "X-ZoneFileInfo")
// Handle CORS preflight OPTIONS requests without auth validation
if r.Method == http.MethodOptions {
w.WriteHeader(http.StatusOK)
return
}
err := authkey.ValidateIncomingRequest(r)
if err != nil {
w.WriteHeader(http.StatusUnauthorized)
w.Write([]byte(fmt.Sprintf("error validating authkey: %v", err)))
returnView on GitHub (pinned to a4447c1563)
Solutions
- Read the panic message in the 500 response body and the server log entry from PanicHandler to locate the panicking handler and stack trace.
- Fix the underlying nil/ out-of-range bug in the wrapped handler function.
- Add defensive checks (nil maps, len() guards, ok-style type assertions) in the handler before dereferencing.
- If the client should receive structured JSON errors, register the route with WebFnOpts{JsonErrors: true} so panics are marshaled via marshalReturnValue instead of plain text.
- Reproduce locally with a request matching the handler's expected parameters and confirm the 500 no longer occurs.
Example fix
// before: unchecked slice access in a WebFnWrap'd handler
parts := strings.Split(r.URL.Path, "/")
use(parts[2]) // panics on short paths
// after
if len(parts) < 3 {
http.Error(w, "path is required", http.StatusBadRequest)
return
}
use(parts[2]) Defensive patterns
Strategy: try-catch
Validate before calling
// client-side pre-check: nothing prevents a server panic, but validate inputs before calling
if (!params.path || params.path.length === 0) throw new Error("path is required"); Try / catch
const resp = await fetch(url, opts);
if (resp.status === 500) {
const msg = await resp.text();
throw new Error(`handler panic: ${msg}`);
}
// JSON-errors routes: parse {isError, error} from the 200 body
const body = await resp.json();
if (body.isError) throw new Error(body.error); Prevention
- Wrap risky handler logic with nil/length checks before dereferencing request data.
- Register web routes with JsonErrors: true so panics come back as structured JSON.
- Watch server logs for PanicHandler stack traces and fix them immediately.
- Cover handlers with tests that send missing/short query parameters.
When it happens
Trigger: Any handler wrapped with WebFnWrap panics (nil dereference, index out of range, failed type assertion) while opts.JsonErrors is false. The panic string becomes the response body with status 500.
Common situations: Developers hit this when a query parameter is missing and the handler indexes into an empty slice, when a JSON field is absent and a cast like r.URL.Query().Get(...) is used unchecked downstream, or after a refactor introduced a nil map/slice access in a web endpoint.
Related errors
- internal server error: %v
- wcloud endpoint not set
- wcloud ping endpoint not set
- failed to copy from file: %v
- failed to copy from reader: %v
AI-assisted analysis of wavetermdev/waveterm@a4447c1563 (2026-09-01).
Data as JSON: /api/errors/4be772fe408be07a.
Report an issue: GitHub.