Hmbown/CodeWhale · error · Error

${envelope.error}

Error message

${envelope.error}

What it means

Every in-place memory edit (edit/retire/revise) must carry evidence, and normalize_evidence runs that evidence through normalize_note: CR/LF are normalized, lines are trimmed, blank lines dropped, and the result must be non-empty and at most 64 KiB (MAX_NOTE_BYTES). This error means the evidence collapsed to an empty string (it was empty, whitespace-only, or only blank lines) — the size overflow surfaces as a different message. The journal treats an unexplained rewrite of durable context as the exact failure mode it exists to prevent.

Source

Thrown at crates/workflow-js/src/vm.rs:1066

  const hostPhase = __workflow_phase;
  const hostBudgetTotal = __workflow_budget_total;
  const hostBudgetSpent = __workflow_budget_spent;
  const hostBudgetRemaining = __workflow_budget_remaining;

  const MAX_ITEMS = __MAX_ITEMS__;
  const taskErrorText = (err) => String(err && err.message !== undefined ? err.message : err);
  const isFatalTaskError = (err) => {
    const text = taskErrorText(err);
    return text.includes("responseSchema") || text.includes("run cancelled");
  };

  globalThis.task = async (opts) => {
    if (opts === null || typeof opts !== "object") {
      throw new TypeError("task(): expected an options object");
    }
    const envelope = JSON.parse(await hostTask(JSON.stringify(opts)));
    if (envelope.error !== undefined) {
      throw new Error(envelope.error);
    }
    return envelope.value;
  };

  globalThis.parallel = (thunks) => {
    if (!Array.isArray(thunks)) {
      throw new TypeError("parallel(): expected an array of thunks");
    }
    if (thunks.length > MAX_ITEMS) {
      throw new Error("parallel(): max " + MAX_ITEMS + " items per call");
    }
    return Promise.all(thunks.map((thunk) => {
      try {
        return Promise.resolve(typeof thunk === "function" ? thunk() : thunk).catch((err) => {
          if (isFatalTaskError(err)) throw err;
          hostLog("parallel(): dropped a failed slot as null: " + String((err && err.message) || err));
          return null;
        });

View on GitHub (pinned to 8880682c63)

Solutions

  1. Pass a concrete, non-blank evidence string describing what changed and why, e.g. "user corrected build command to `pnpm build`".
  2. If evidence comes from a variable, default it: evidence.is_empty() fallback before calling edit.
  3. Check for the 64 KiB cap too — normalize_evidence shares MAX_NOTE_BYTES with notes, so trim oversized evidence.

Example fix

// before
store.edit(scope, id, from, to, "")?;

// after
let evidence = evidence.trim();
let evidence = if evidence.is_empty() { "manual correction during review" } else { evidence };
store.edit(scope, id, from, to, evidence)?;
Defensive patterns

Strategy: validation

Validate before calling

fn usable_evidence(evidence: &str) -> bool {
    let collapsed: String = evidence.lines().map(str::trim).filter(|l| !l.is_empty()).collect();
    !collapsed.is_empty() && collapsed.len() <= 64 * 1024
}

if !usable_evidence(&evidence) {
    anyhow::bail!("provide a short non-empty justification for this memory edit");
}
store.edit(scope, id, from, to, &evidence)?;

Type guard

fn is_non_empty_evidence(e: &str) -> bool {
    e.lines().any(|l| !l.trim().is_empty())
}

Try / catch

match store.edit(scope, id, &from, &to, evidence) {
    Ok(hit) => hit,
    Err(e) if e.to_string().contains("memory edits require non-empty evidence") =>
        store.edit(scope, id, &from, &to, "unspecified manual edit")?,
    Err(e) => return Err(e),
}

Prevention

When it happens

Trigger: Calling store.edit(...) or retire(...) with evidence="", evidence=" ", or a string of only newlines/spaces; model tool-calls that fabricate an evidence argument from an empty variable.

Common situations: LLM agents calling the memory-edit tool without filling the evidence parameter; scripts templating evidence from an environment variable that is unset; whitespace introduced by trimming upstream.

Related errors


AI-assisted analysis of Hmbown/CodeWhale@8880682c63 (2026-08-16). Data as JSON: /api/errors/9305e7d08f278b5d. Report an issue: GitHub.