Hmbown/CodeWhale · error · TypeError

task(): expected an options object

Error message

task(): expected an options object

What it means

Raised by NativeMemoryStore::delete_all when asked to wipe workspace-scoped memory without identifying which workspace. Because each workspace has its own directory under root/workspace/<sha256-of-origin>/, a Workspace deletion with workspace_id=None is ambiguous and the store refuses rather than deleting every workspace or none. The command layer resolves this by first calling workspace_id(cwd); when that returns None it reports that there is nothing workspace-scoped to delete.

Source

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

  // Capture temporary host bindings into this closure, then strip them from
  // globalThis so scripts only see the documented Workflow surface (#4129).
  const hostTask = __workflow_task;
  const hostLog = __workflow_log;
  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) => {

View on GitHub (pinned to 8880682c63)

Solutions

  1. Resolve the id and handle the None case as a no-op, matching commands/groups/memory/memory.rs: if workspace_id(cwd)? is None, report 'no workspace memory for this directory' and skip deletion.
  2. Add an origin remote if the workspace memory you want to erase belongs to this checkout: git remote add origin <url>.
  3. To erase everything including all workspaces, call delete_all(None, None) instead of guessing a scope.

Example fix

// before
store.delete_all(Some(MemoryScope::Workspace), None)?;

// after
match NativeMemoryStore::workspace_id(&cwd)? {
    Some(id) => store.delete_all(Some(MemoryScope::Workspace), Some(&id))?,
    None => {} // no origin remote: nothing workspace-scoped to delete
}
Defensive patterns

Strategy: validation

Validate before calling

match NativeMemoryStore::workspace_id(&cwd)? {
    Some(id) => store.delete_all(Some(MemoryScope::Workspace), Some(&id))?,
    None => { /* nothing workspace-scoped here; no-op */ }
}

Try / catch

match store.delete_all(Some(MemoryScope::Workspace), ws_id) {
    Ok(()) => {}
    Err(e) if e.to_string().contains("workspace scope requires a workspace id") => {
        eprintln!("no workspace memory for this directory (no git origin remote)");
    }
    Err(e) => return Err(e),
}

Prevention

When it happens

Trigger: store.delete_all(Some(MemoryScope::Workspace), None) — e.g. a `/memory erase workspace` command executed in a directory with no git origin, or API misuse passing None explicitly.

Common situations: Users running memory-erase commands outside a git repo; repos without an origin remote; automation calling delete_all with a scope filter but forgetting the id argument.

Related errors


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