From 77ae06bfaa018f9e687ceebb46c9af50e0eb3d26 Mon Sep 17 00:00:00 2001 From: Ayaan Zaidi Date: Tue, 5 May 2026 21:14:32 +0530 Subject: [PATCH] fix: skip compile cache permission warnings (#76362) (thanks @neeravmakwana) --- CHANGELOG.md | 1 + scripts/postinstall-bundled-plugins.mjs | 10 ++++ .../postinstall-bundled-plugins.test.ts | 51 +++++++++++++++++++ 3 files changed, 62 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 57b5f01fb51..70ad5355df4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -328,6 +328,7 @@ Docs: https://docs.openclaw.ai - Config/recovery: chmod restored `openclaw.json` back to owner-only (`0600`) after suspicious-read backup recovery on POSIX hosts, so a previously world-readable config mode cannot persist into a freshly restored credential-bearing config. (#77488) Thanks @drobison00. - Memory/dreaming: persist last dreaming-ingestion calendar day per daily note in `daily-ingestion.json` so unchanged notes are still re-ingested once per dreaming day for promotion signals toward deep thresholds. Fixes #76225. (#76359) Thanks @neeravmakwana. - Agents/embed: keep message_end safety delivery armed when a silent text_end chunk produces no block reply, fixing dropped Telegram/forum replies. Fixes #77833. (#77840) Thanks @neeravmakwana. +- Install/postinstall: skip noisy compile-cache prune warnings when `EACCES`/`EPERM` prevent removing shared `/tmp/node-compile-cache` entries owned by another user. Fixes #76353. (#76362) Thanks @RayWoo and @neeravmakwana. ## 2026.5.3-1 diff --git a/scripts/postinstall-bundled-plugins.mjs b/scripts/postinstall-bundled-plugins.mjs index ac00cfb6083..f4595f172bc 100644 --- a/scripts/postinstall-bundled-plugins.mjs +++ b/scripts/postinstall-bundled-plugins.mjs @@ -814,6 +814,10 @@ function shouldRunBundledPluginPostinstall(params) { return true; } +function isCompileCachePrunePermissionDenied(error) { + return error?.code === "EACCES" || error?.code === "EPERM"; +} + export function pruneOpenClawCompileCache(params = {}) { const env = params.env ?? process.env; const pathExists = params.existsSync ?? existsSync; @@ -842,10 +846,16 @@ export function pruneOpenClawCompileCache(params = {}) { retryDelay: 100, }); } catch (error) { + if (isCompileCachePrunePermissionDenied(error)) { + continue; + } log.warn?.(`[postinstall] could not prune OpenClaw compile cache: ${String(error)}`); } } } catch (error) { + if (isCompileCachePrunePermissionDenied(error)) { + continue; + } log.warn?.(`[postinstall] could not prune OpenClaw compile cache: ${String(error)}`); } } diff --git a/test/scripts/postinstall-bundled-plugins.test.ts b/test/scripts/postinstall-bundled-plugins.test.ts index 744fea8792c..46ad8913045 100644 --- a/test/scripts/postinstall-bundled-plugins.test.ts +++ b/test/scripts/postinstall-bundled-plugins.test.ts @@ -147,6 +147,57 @@ describe("bundled plugin postinstall", () => { ); }); + it("does not warn when compile-cache pruning hits EACCES or EPERM (shared caches)", () => { + const base = path.join("/tmp", "openclaw-shared-compile-cache"); + const dirA = path.join(base, "v22.13.1-x64-efe9a9df-1001"); + const dirB = path.join(base, "v22.13.1-x64-efe9a9df-1002"); + const warn = vi.fn(); + const rmSync = vi.fn((value: string) => { + if (value === dirA) { + throw Object.assign(new Error(`permission denied pruning ${value}`), { code: "EACCES" }); + } + if (value === dirB) { + throw Object.assign(new Error(`operation not permitted pruning ${value}`), { + code: "EPERM", + }); + } + }); + + pruneOpenClawCompileCache({ + env: { NODE_COMPILE_CACHE: base }, + existsSync: vi.fn((value: string) => value === base), + readdirSync: vi.fn(() => [ + { name: path.basename(dirA), isDirectory: () => true }, + { name: path.basename(dirB), isDirectory: () => true }, + ]), + rmSync, + log: { warn }, + }); + + expect(rmSync).toHaveBeenCalledTimes(2); + expect(warn).not.toHaveBeenCalled(); + }); + + it("does not warn when the compile-cache base directory cannot be listed (EACCES)", () => { + const base = path.join("/tmp", "openclaw-compile-cache-no-list"); + const warn = vi.fn(); + const rmSync = vi.fn(); + const err = Object.assign(new Error(`EACCES: ${base}`), { code: "EACCES" }); + + pruneOpenClawCompileCache({ + env: { NODE_COMPILE_CACHE: base }, + existsSync: vi.fn(() => true), + readdirSync: vi.fn(() => { + throw err; + }), + rmSync, + log: { warn }, + }); + + expect(rmSync).not.toHaveBeenCalled(); + expect(warn).not.toHaveBeenCalled(); + }); + it("does not classify published packages with source files as source checkouts", () => { const packageRoot = "/pkg"; const existingPaths = new Set([