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
query_worker_observability requires $workers.outcome to be a string on every returned event. Because the response is validated with .parse() over the whole array, a single event without outcome throws away the entire response — the tool returns no logs at all.
outcome (ok / exception / canceled) describes a whole invocation. Cloudflare attaches it to the invocation-summary line ($metadata.type = "cf-worker-event"). Individual console.log lines emitted inside an invocation ($metadata.type = "cf-worker") are not invocations and legitimately have no outcome. The API is behaving correctly; the schema's assumption that every event is an invocation is what's wrong.
This is the same class of bug as #362 (schema too strict for a heterogeneous event stream). The workflow enum value and the cpuTimeMs/wallTimeMs fields named there appear to have been addressed since, but outcome is the remaining — and highest-impact — instance of the pattern.
exportconstzCloudflareMiniEvent=z.object({event: zCloudflareMiniEventDetails,scriptName: z.string(),outcome: z.string(),// <-- required, but absent on every console.log lineeventType: z.enum([...]),requestId: z.string(),
...
})
packages/mcp-common/src/cloudflare-api.ts (line ~67) parses the whole payload and throws on the first failure:
if(responseSchema){returnresponseSchema.parse(data)// one bad event => entire response lost}
Because zCloudflareEvent extends zCloudflareMiniEvent, both branches of the union require outcome, which is why the surfaced error is invalid_union with path: ["outcome"] in both branches.
Measured impact
Measured against 1,816 real production events from one Worker over one day (2026-07-16), grouped by $metadata.type:
events
has outcome
missing outcome
total
1,816
976 (53.7%)
840 (46.3%)
cron
680
96
584 (86%)
fetch
1,136
880
256
The split is exactly along $metadata.type: all 976 cf-worker-event rows have outcome; all 840 cf-worker rows do not.
It fails hardest on cron logs — 86% missing — which is exactly what you need to read during an outage.
Reproduced live against a 35-minute production window containing a real incident: the tool returned zero events and ~30k characters of Zod errors. Every one of the 5 diagnostic console.log events needed to explain that incident was discarded, because all 5 were cf-worker lines with no outcome. Querying the same window over the raw REST endpoint returns all 84 events.
Reproduction
Any Worker that calls console.log() inside a request or scheduled handler will reproduce this. Minimal synthetic event that fails validation (this is the shape the API returns for a console.log line inside a cron invocation):
{
"$workers": {
"event": { "cron": "*/15 * * * *", "scheduledTime": 1784222146000 },
"scriptName": "my-worker",
"eventType": "cron",
"executionModel": "stateless",
"requestId": "1RI7X6A7OCMC159U"// no "outcome" — this is correct API output, but fails zCloudflareMiniEvent
}
}
Result: Error analyzing worker logs: [ ... "path": ["outcome"], "message": "Invalid input: expected string, received undefined" ... ] repeated per offending event, and no logs returned.
Suggested fix
Make the field optional — it is genuinely absent for a whole legitimate class of event:
outcome: z.string().optional(),
Two adjacent hardening suggestions, worth more than the one-line fix on its own:
Don't fail the batch for one row. Validate events individually (.safeParse() per event) and return the ones that pass, ideally reporting how many were dropped. A logs tool that returns 99% of the data plus a warning is far more useful during an incident than one that returns nothing.
Audit the other required fields on this schema for the same assumption.event, scriptName and requestId are also declared required on zCloudflareMiniEvent; anything not guaranteed on non-invocation rows will cause the identical whole-response failure. This is the third report of that pattern (Workers Observability: eventType 'workflow' not supported in schema #362, and now this).
Happy to open a PR for the one-line change if that's useful — say the word and I'll send it.
Problem
query_worker_observabilityrequires$workers.outcometo be a string on every returned event. Because the response is validated with.parse()over the whole array, a single event withoutoutcomethrows away the entire response — the tool returns no logs at all.outcome(ok/exception/canceled) describes a whole invocation. Cloudflare attaches it to the invocation-summary line ($metadata.type = "cf-worker-event"). Individualconsole.loglines emitted inside an invocation ($metadata.type = "cf-worker") are not invocations and legitimately have nooutcome. The API is behaving correctly; the schema's assumption that every event is an invocation is what's wrong.This is the same class of bug as #362 (schema too strict for a heterogeneous event stream). The
workflowenum value and thecpuTimeMs/wallTimeMsfields named there appear to have been addressed since, butoutcomeis the remaining — and highest-impact — instance of the pattern.Root cause
packages/mcp-common/src/types/workers-logs.types.ts—zCloudflareMiniEvent(line ~251):packages/mcp-common/src/cloudflare-api.ts(line ~67) parses the whole payload and throws on the first failure:Because
zCloudflareEventextendszCloudflareMiniEvent, both branches of the union requireoutcome, which is why the surfaced error isinvalid_unionwithpath: ["outcome"]in both branches.Measured impact
Measured against 1,816 real production events from one Worker over one day (2026-07-16), grouped by
$metadata.type:outcomeoutcomecronfetchThe split is exactly along
$metadata.type: all 976cf-worker-eventrows haveoutcome; all 840cf-workerrows do not.It fails hardest on cron logs — 86% missing — which is exactly what you need to read during an outage.
Reproduced live against a 35-minute production window containing a real incident: the tool returned zero events and ~30k characters of Zod errors. Every one of the 5 diagnostic
console.logevents needed to explain that incident was discarded, because all 5 werecf-workerlines with nooutcome. Querying the same window over the raw REST endpoint returns all 84 events.Reproduction
Any Worker that calls
console.log()inside a request or scheduled handler will reproduce this. Minimal synthetic event that fails validation (this is the shape the API returns for aconsole.logline inside a cron invocation):{ "$workers": { "event": { "cron": "*/15 * * * *", "scheduledTime": 1784222146000 }, "scriptName": "my-worker", "eventType": "cron", "executionModel": "stateless", "requestId": "1RI7X6A7OCMC159U" // no "outcome" — this is correct API output, but fails zCloudflareMiniEvent } }Then:
Result:
Error analyzing worker logs: [ ... "path": ["outcome"], "message": "Invalid input: expected string, received undefined" ... ]repeated per offending event, and no logs returned.Suggested fix
Make the field optional — it is genuinely absent for a whole legitimate class of event:
Two adjacent hardening suggestions, worth more than the one-line fix on its own:
.safeParse()per event) and return the ones that pass, ideally reporting how many were dropped. A logs tool that returns 99% of the data plus a warning is far more useful during an incident than one that returns nothing.event,scriptNameandrequestIdare also declared required onzCloudflareMiniEvent; anything not guaranteed on non-invocation rows will cause the identical whole-response failure. This is the third report of that pattern (Workers Observability: eventType 'workflow' not supported in schema #362, and now this).Happy to open a PR for the one-line change if that's useful — say the word and I'll send it.