fix(browser): handled stackless cmux rejections

Attributed unmatched rejection reasons when exactly one cmux guest run is active, covering primitive and library-created failures without guessing between concurrent runs. Updated the process probe to reject with a primitive value.

Fixes #7365
This commit is contained in:
roboomp
2026-08-02 09:31:21 +00:00
parent 8d4521db78
commit 6113fe9727
2 changed files with 36 additions and 27 deletions
@@ -270,36 +270,45 @@ const recentCmuxRunFiles = new Set<string>();
function consumeCmuxRunRejection(reason: unknown): boolean {
const stack = reason instanceof Error && typeof reason.stack === "string" ? reason.stack : undefined;
if (!stack) return false;
if (stack) {
let owner: ActiveCmuxRun | undefined;
let ownerIndex = -1;
for (const run of activeCmuxRuns.values()) {
const index = stack.lastIndexOf(run.filename);
if (index > ownerIndex) {
ownerIndex = index;
owner = run;
}
}
if (owner) {
owner.floatingRejections.push(reason);
return true;
}
let owner: ActiveCmuxRun | undefined;
let ownerIndex = -1;
for (const run of activeCmuxRuns.values()) {
const index = stack.lastIndexOf(run.filename);
if (index > ownerIndex) {
ownerIndex = index;
owner = run;
let recent: string | undefined;
let recentIndex = -1;
for (const filename of recentCmuxRunFiles) {
const index = stack.lastIndexOf(filename);
if (index > recentIndex) {
recentIndex = index;
recent = filename;
}
}
if (recent) {
logger.warn("Unhandled rejection from a finished cmux browser run (missing await?)", {
filename: recent,
error: reason,
});
return true;
}
}
if (owner) {
owner.floatingRejections.push(reason);
return true;
}
let recent: string | undefined;
let recentIndex = -1;
for (const filename of recentCmuxRunFiles) {
const index = stack.lastIndexOf(filename);
if (index > recentIndex) {
recentIndex = index;
recent = filename;
}
}
if (!recent) return false;
logger.warn("Unhandled rejection from a finished cmux browser run (missing await?)", {
filename: recent,
error: reason,
});
// Rejection interceptors receive no promise identity. With one live cmux run,
// it is the only guest owner available for stackless or library-created reasons.
if (activeCmuxRuns.size !== 1) return false;
const only = activeCmuxRuns.values().next().value;
if (!only) return false;
only.floatingRejections.push(reason);
return true;
}
@@ -18,7 +18,7 @@ try {
await runCmuxCode(tab, {
code: \`
const { promise, reject } = Promise.withResolvers();
reject(new Error("boom"));
reject("boom");
await Bun.file("package.json").text();
await promise.catch(() => undefined);
\`,