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
- 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.
- Re-run the install — the rollback already cleaned the bad copy, and a transient staging race is resolved by a fresh stage.
- 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
- Keep the manifest at the bundle root in every packaging step; test the packaged artifact, not the source tree.
- Do not filter plugin.json/kimi.plugin.json/plugin.toml out of archives or copy scripts.
- Avoid concurrent installs into the same plugins directory; serialize installs.
- Rely on the built-in rollback: after this error, clean up and retry rather than leaving partial state.
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
- pipeline(): max ${MAX_ITEMS} items per call
- Thread summaries require the runtime bearer token.
- Restore points require the runtime bearer token.
- Restore points returned HTTP ${response.statusCode}.
- pipeline(): expected an array of items
AI-assisted analysis of Hmbown/CodeWhale@8880682c63 (2026-08-16).
Data as JSON: /api/errors/fc8f7236ed5a16da.
Report an issue: GitHub.