Hmbown/CodeWhale · error · Error

parallel(): max ${MAX_ITEMS} items per call

Error message

parallel(): max ${MAX_ITEMS} items per call

What it means

After place() copies the staged bundle into its final directory under the user plugins dir, resolve_manifest_path fails to find any of plugin.json, kimi.plugin.json, or plugin.toml at the bundle root. This is a post-copy integrity check: the manifest existed during staging (validate_staged passed), but the final tree does not have one at its root. The installer rolls back — it removes the copied directory and restores any backup it took — so no half-installed plugin remains.

Source

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

  };

  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;
        });
      } catch (err) {
        if (isFatalTaskError(err)) return Promise.reject(err);
        hostLog("parallel(): dropped a failed slot as null: " + String((err && err.message) || err));
        return null;
      }
    }));
  };

  globalThis.pipeline = (items, ...stages) => {
    if (!Array.isArray(items)) {

View on GitHub (pinned to 8880682c63)

Solutions

  1. Verify the bundle layout: the directory you install must contain plugin.json (or kimi.plugin.json / plugin.toml) directly at its root, not one level down.
  2. Re-run the install — the rollback already cleaned the bad copy, and a transient staging race is resolved by a fresh stage.
  3. If building the bundle yourself, ensure the manifest is copied into the archive/checkout root and not filtered out.

Example fix

# before: repo root staged, manifest lives in ./plugins/my-plugin/plugin.json
plugin install ./my-plugin-repo

# after: stage the bundle directory that actually holds the manifest
plugin install ./my-plugin-repo/plugins/my-plugin
Defensive patterns

Strategy: validation

Validate before calling

// before installing, confirm the bundle you ship actually has a root manifest
let manifest_ok = ["plugin.json", "kimi.plugin.json", "plugin.toml"]
    .iter().any(|m| final_bundle_dir.join(m).is_file());
assert!(manifest_ok, "bundle must keep its manifest at the root after copy");

Type guard

fn has_root_manifest(bundle: &Path) -> bool {
    ["plugin.json", "kimi.plugin.json", "plugin.toml"].iter()
        .any(|m| bundle.join(m).is_file())
}

Try / catch

match install_plugin(source).await {
    Ok(rec) => rec,
    Err(e) if e.to_string().contains("installed plugin has no supported manifest") => {
        // rollback already ran; fix the bundle layout and retry the install once
        return Err(e).context("bundle layout lost its root manifest during copy"));
    }
    Err(e) => return Err(e),
}

Prevention

When it happens

Trigger: A race where the staged tree changes between staging and copy; a bundle whose manifest sits in a nested subdirectory so the copy lands the manifest below the root; an install pipeline that rewrites/repacks the staged tree and drops the manifest.

Common situations: Installing from a git checkout or tarball where the plugin lives in a subdirectory and the wrong root was staged; concurrent plugin installs mutating the same staging area; packaging scripts that exclude the manifest (e.g. .gitignore-style filtering applied to plugin.json).

Related errors


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