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

  1. Pass a real boolean: Boolean(value) or compare the raw value explicitly (value === 'true').
  2. Coerce env/CLI input before constructing the options object.
  3. 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

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


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)