Hmbown/CodeWhale · error · TypeError
includeProgress must be a boolean
Error message
includeProgress must be a boolean
What it means
threadEvents() accepts includeProgress to request replay progress markers in the event stream. This TypeError is thrown when includeProgress is provided but is not exactly a boolean. The SDK checks the type strictly because the flag is serialized as a query parameter and also gates a capability check on the response.
Solutions
- Pass a real boolean: Boolean(value) or compare the raw value explicitly (value === 'true').
- Coerce env/CLI input before constructing the options object.
- Omit includeProgress when you do not need progress markers.
Example fix
// before
await client.threadEvents(id, { includeProgress: process.env.SHOW_PROGRESS });
// after
await client.threadEvents(id, { includeProgress: process.env.SHOW_PROGRESS === "true" }); Defensive patterns
Strategy: validation
Validate before calling
const includeProgress = process.env.SHOW_PROGRESS === "true";
if (includeProgress !== undefined && typeof includeProgress !== "boolean") throw new TypeError("includeProgress must be boolean"); Type guard
const isBool = (v) => v === undefined || typeof v === "boolean";
Try / catch
try { yield* client.threadEvents(id, { includeProgress }); } catch (err) { if (err instanceof TypeError && err.message.includes("boolean")) throw new Error("caller bug: includeProgress must be a real boolean"); throw err; } Prevention
- Coerce env/CLI/config strings to booleans at the boundary, not at the call site.
- Enable TypeScript strict typing for the options object so non-boolean flags are caught at compile time.
When it happens
Trigger: Calling threadEvents(id, { includeProgress: 'true' }), { includeProgress: 1 }, or { includeProgress: null } — any defined non-boolean value.
Common situations: Boolean flags read from env vars or CLI strings ('true'/'false') passed through unconverted; options objects built generically from JSON where 0/1 was used.
Understand the failure class
Background: Type mismatch errors: IllegalArgumentException, TypeError and type guards across 150 open-source libraries — this error's family across 150 libraries.
Related errors
- expected a notification boolean
- must be a nonnegative safe integer
- Runtime API path segment must be a non-empty value
- 1
- A pinned task provider requires an explicit model
AI-assisted analysis of Hmbown/CodeWhale@433685b202 (2026-09-15).
Data as JSON: /api/errors/0af491fc747ab23b.
Report an issue: GitHub.
Appendix: source
Thrown at npm/runtime-sdk/index.js:136
method: "GET",
path,
});
}
for await (const event of parseEventStream(response.body)) {
yield event;
}
}
/** Read the existing durable thread journal. This never starts a turn. */
async *threadEvents(threadId, options = {}) {
const query = new URLSearchParams();
for (const [key, value] of [["since_seq", options.sinceSeq], ["replay_limit", options.replayLimit]]) {
if (value === undefined) continue;
if (!Number.isSafeInteger(value) || value < 0) throw new TypeError(`${key} must be a nonnegative safe integer`);
query.set(key, String(value));
}
if (options.includeProgress !== undefined && typeof options.includeProgress !== "boolean")
throw new TypeError("includeProgress must be a boolean");
if (options.includeProgress) query.set("progress", "true");
const path = `/v1/threads/${segment(threadId)}/events?${query}`;
const response = await this.#rawRequest(path, {
method: "GET", capability: "thread_event_stream", accept: "text/event-stream",
signal: options.signal, redirect: "error",
});
if (!response.body || !/^text\/event-stream(?:;|$)/i.test(response.headers.get("content-type") ?? "")) {
await response.body?.cancel();
throw new RuntimeApiError("Runtime thread response is not an event stream", { method: "GET", path });
}
if (options.includeProgress && response.headers.get("x-codewhale-event-progress") !== "1") {
await response.body.cancel();
throw new RuntimeCapabilityError("thread_event_progress", "Runtime does not support thread replay progress", { method: "GET", path, status: 501 });
}
yield* parseEventStream(response.body, { maxFrameChars: 2 * 1024 * 1024, requireBoundary: true });
}
async #jsonRequest(path, options = {}) {View on GitHub (pinned to 433685b202)