You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Commit 45461ba
Browse filesBrowse the repository at this point in the historyBrowse files
Show why hosted requests and cron jobs fail (#395)
## Problem
A hosted app (napi-rs) returned about 100 worker 500s in one day. The
5xx alert email pointed to `void project requests` and `void project
logs`. Neither command showed the cause:
```
$ void project requests --status 5xx
16:30:14 GET 500 static 1897ms <- the worker answered, but the label says "static"
$ void project logs --level error
16:30:12 GET https://napi.rs/sponsors.svg 500
[error] TypeError: Cannot read properties of undefined (reading 'href')
<- no stack, although the API returns it
13:00:25 POST https://internal/__void/scheduled 500
[error] AggregateError: Scheduled jobs failed
<- which job failed, and why, is lost
```
Three causes:
```
request label dispatch: a path with a file extension (/sponsors.svg) stays "static",
even when the app's own route answered it
logs stack CLI: prints only `Name: message`; drops errorInfo[].stack and exception.stack
cron error runtime: Workers log capture keeps an error's own message and stack,
but not AggregateError.errors, so the inner errors vanish
```
## What this PR changes
```
request label (dispatch metering)
dotted path on an SSR deploy, no platform failure
├─ manifest says "not a file" and the worker answers the path ─> ssr
├─ worker owns the path and returns 5xx or times out ─────────> ssr
└─ listed file, asset-layer answer, platform asset failure ───> static (unchanged)
The ISR write-back checks the path directly, so these routes never enter the ISR cache.
void project logs
[error] TypeError: Cannot read properties of undefined (reading 'href')
at assets/resvg-gkFxLqVH.js:14881:64 <- dimmed frames under the
at assets/resvg-gkFxLqVH.js:15409:3 argument that logged them
[exception] frames print the same way
scheduled jobs
job fails ─> console.error('[void] Scheduled job crons/x.ts failed for cron "0 5 * * *":', error)
(logged at once, with the original error, so its stack is kept)
all jobs done ─> throw AggregateError(errors, 'Scheduled jobs failed: crons/x.ts')
(HTTP 500 and the shared onError are unchanged)
```
Real output from this branch's CLI against the live napi-rs data:
```
15:23:32 GET https://napi.rs/sponsors.svg 500
[error] TypeError: Cannot read properties of undefined (reading 'href')
at assets/resvg-gkFxLqVH.js:14881:64
at assets/resvg-gkFxLqVH.js:15409:3
at new Promise (<anonymous>)
at assets/resvg-gkFxLqVH.js:15408:19
at assets/client-7iHZB5sW.js:16:49
```
## Decisions
| Question | Decision | Why |
|---|---|---|
| How does dispatch know the worker answered? | Reuse the asset-manifest
answer it already reads for the static cache | No new KV read on the hot
path |
| New request type such as `worker`? | No, use `ssr` | The CLI, docs and
usage queries already know `ssr` |
| Fix cron errors in the shared Hono `onError`? | No, in the scheduled
runner | `onError` serves every route; the runner knows the job file and
cron |
| Change the platform API or tail worker for stacks? | No, CLI only |
The API already returns `errorInfo[].stack` and `exception.stack` |
| `void platform deployment logs` (operator command) | Not changed |
Outside the reported problem |
## Rollout
```
merge ─> release void ──> users upgrade the CLI ──────> stacks print (no redeploy needed)
└──> apps redeploy ──────────────> cron errors named
deploy hosted dispatch ─────────────────────────> new rows labeled ssr
(old Analytics rows keep "static")
```
## Known limits
- Some app routes on paths with a file extension can still be labeled
`static` when they succeed or return 4xx. This applies to requests with
a Cookie or Authorization header, to HEAD, Range and POST requests, and
to SSR apps that uploaded no static files. On framework deploys, these
requests also stay `static` when they fail with a 5xx. A correct label
would need an asset-manifest read on every credentialed asset request.
That is too much cost for a display label. On Void SSR apps, server
errors are labeled `ssr` for every request shape.
- A failed cron now shows two log lines on the hosted path: the per-job
line and the `AggregateError` line.
- Framework cron runners and queue runners have the same error-loss
pattern. They are not changed here.
## Testing
| Check | Result |
|---|---|
| New tests on old code | fail (dispatch 7+, logs rendering 1, scheduled
dispatch 2) |
| Changed test files | 5 files, 353 tests pass |
| `vp run test --base origin/main` | 475 files, 10329 tests pass |
| `vp lint`, `vp run check` | pass (31 typecheck tasks) |
| `vp test run` | 689 files pass. 1 file failed on a port race in the
Solid dev-server test: the test waited on a port that `vp dev` found
busy. It passes on rerun. The race is fixed in #396. |
| Branch CLI against live napi-rs logs | frames print under every error
|
| `vp dev` fixture with one failing cron job | per-job line with file,
cron, message and stack; the other job runs; HTTP 500 |
🤖 Generated with [Claude Code](https://claude.com/claude-code)
---------
Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Logs include top-level `console.*` calls and uncaught errors captured by Cloudflare Tail. If you catch an error and save it only to your database, it won't appear here. Also log it with `console.error()` or `logger.error()` from `void/log`.
141
+
Logs include top-level `console.*` calls and uncaught errors captured by Cloudflare Tail. If you catch an error and save it only to your database, it won't appear here. Also log it with `console.error()` or `logger.error()` from `void/log`. On hosted Void targets, pass the `Error` object itself to `console.error()`, as in `console.error('Save failed:', error)`, to see its stack trace under the log line. Logging only `error.message` shows no stack.
142
142
143
143
For errors that never reach your Worker, such as edge routing errors or static site requests, use `void project requests --status 5xx`.
0 commit comments