Frontend Error Reporting
TL;DR — zero config needed
The starter app deployed by create_project already has frontend error reporting active. It wraps the handler with withErrorReporting, which auto-injects a <script> into every HTML response. No listeners to write, no client code to add.
If you wrote a custom handler, add one line:
import { withErrorReporting } from "./.onvibe/helpers.ts";
async function handler(req: Request): Promise<Response> {
return new Response("<!DOCTYPE html>...", {
headers: { "content-type": "text/html; charset=utf-8" },
});
}
export default withErrorReporting(handler); // ← this is all you need
./.onvibe/helpers.ts is injected by the platform at deploy time — do not include it in your source files.
How withErrorReporting works
- All requests pass through to your handler unchanged.
- For responses with
Content-Type: text/html, the HOF injects a<script>before</head>(or prepended if missing) that:- Hooks
window.onerror— catches uncaught synchronous exceptions and script errors. - Hooks
window.addEventListener('unhandledrejection', ...)— catches unhandled Promise rejections. - POSTs each error to
/.onvibe/exceptionsasynchronously (fire-and-forget, never blocks the UI).
- Hooks
- Non-HTML responses (JSON, images, plain text) are passed through untouched.
The /.onvibe/exceptions endpoint
Every deployed app exposes this route at the same origin:
POST /.onvibe/exceptions
Content-Type: application/json
The runner intercepts POST /.onvibe/exceptions before passing control to your handler — no auth required from the browser (same-origin only). GET falls through to your handler.
Accepted payload fields
| Field | Type | Description |
|---|---|---|
message |
string | Error message (required) |
stack |
string | Full stack trace as returned by err.stack |
url |
string | window.location.href at the time of the error |
timestamp |
string | ISO 8601 timestamp |
Note: Fields such as
source,line,col, andkindare accepted but not currently persisted separately. Include them in thestackstring if you need them (e.g.src + ':' + line + ':' + colwhenerr.stackis unavailable).
The endpoint always returns 204 No Content.
Viewing captured errors
Use get_exceptions. Each row includes a type field:
| type | Source |
|---|---|
backend |
Unhandled server-side exception caught by the runner |
frontend |
Browser-side JS error reported via /.onvibe/exceptions |
[
{
"type": "frontend",
"message": "Cannot read properties of undefined (reading 'id')",
"stack": "TypeError: Cannot read properties of undefined...\n at handler (https://myapp.onvibe.run/:12:5)",
"request_url": "https://myapp.onvibe.run/dashboard",
"occurred_at": "2025-01-01T12:00:00Z"
}
]
Known browser limitations
- Errors inside setTimeout / setInterval: The stack trace loses the original call site. Only the frame where the
throwhappens is captured, not the chain that scheduled it. For richer stacks, throw closer to the origin or useasync/awaitinstead of callbacks (unhandledrejectioncaptures the full async chain). - Cross-origin scripts: Errors from scripts loaded from a different origin arrive as
"Script error."with no stack. Addcrossorigin="anonymous"to the<script>tag and ensure the script host sendsAccess-Control-Allow-Origin: *. - Stack format varies by browser: Chrome uses
at func (url:line:col); Firefox usesfunc/<@url:line:col. The raw stack string is stored as-is.
Manual integration (advanced)
Only needed if you cannot use withErrorReporting (e.g. a pre-rendered static site with no server handler):
window.onerror = function(msg, src, line, col, err) {
fetch('/.onvibe/exceptions', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
message: String(msg),
stack: err ? err.stack : (src + ':' + line + ':' + col),
url: window.location.href,
timestamp: new Date().toISOString(),
}),
}).catch(function(){});
return false;
};
window.addEventListener('unhandledrejection', function(e) {
var err = e.reason;
fetch('/.onvibe/exceptions', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
message: err instanceof Error ? err.message : String(err),
stack: err instanceof Error ? err.stack : undefined,
url: window.location.href,
timestamp: new Date().toISOString(),
}),
}).catch(function(){});
});
Constraints
- Errors are stored per-project, capped at the last 10 entries.
- No CORS headers — the endpoint is for same-origin use only.