fix: make letta update resilient to npm extraction race conditions (#1201)

This commit is contained in:
cthomas
2026-02-27 14:54:02 -08:00
committed by GitHub
parent 1a245d74d3
commit bb5d7d0a39
2 changed files with 27 additions and 1 deletions

View File

@@ -70,7 +70,7 @@
"test:update-chain:manual": "bun run src/tests/update-chain-smoke.ts --mode manual", "test:update-chain:manual": "bun run src/tests/update-chain-smoke.ts --mode manual",
"test:update-chain:startup": "bun run src/tests/update-chain-smoke.ts --mode startup", "test:update-chain:startup": "bun run src/tests/update-chain-smoke.ts --mode startup",
"prepublishOnly": "bun run build", "prepublishOnly": "bun run build",
"postinstall": "node scripts/postinstall-patches.js" "postinstall": "node scripts/postinstall-patches.js || echo letta: vendor patches skipped"
}, },
"lint-staged": { "lint-staged": {
"*.{ts,tsx,js,jsx,json}": [ "*.{ts,tsx,js,jsx,json}": [

View File

@@ -323,6 +323,32 @@ async function performUpdate(): Promise<{
} }
} }
// npm race condition retry: covers TAR_ENTRY_ERROR (parallel extraction races),
// uv_cwd (npm CWD deleted during atomic package swap), and spawn sh ENOENT
// (sharp postinstall CWD missing). All are transient npm parallelism issues.
const isNpmRaceCondition =
pm === "npm" &&
(errorMsg.includes("TAR_ENTRY_ERROR") ||
errorMsg.includes("uv_cwd") ||
(errorMsg.includes("spawn sh") && errorMsg.includes("ENOENT")));
if (isNpmRaceCondition) {
debugLog("npm race condition detected, cleaning up and retrying...");
if (globalPath) {
await cleanupOrphanedDirs(globalPath);
}
try {
await execFileAsync(pm, installArgs, { timeout: 60000 });
debugLog("Update succeeded after race condition retry");
return { success: true };
} catch (retryError) {
const retryMsg =
retryError instanceof Error ? retryError.message : String(retryError);
debugLog("Update failed after race condition retry:", retryMsg);
return { success: false, error: retryMsg };
}
}
debugLog("Update failed:", error); debugLog("Update failed:", error);
return { success: false, error: errorMsg }; return { success: false, error: errorMsg };
} }