ruvnet/ruflo · critical
${failure} Rollback failed: ${rollbackError instanceof Error
Error message
${failure} Rollback failed: ${rollbackError instanceof Error ? rollbackError.message : String(rollbackError)} What it means
When installAndActivateProxy() fails after it had backed up the existing meta-proxy binary, it attempts a rollback (restore old binary/manifest, relaunch the previous daemon). If any rollback step itself throws — stopping the new daemon, restoring files, or relaunching the prior daemon — the original failure is rethrown wrapped with 'Rollback failed: <rollback error>' so both causes are visible.
Source
Thrown at v3/@claude-flow/cli/src/proxy/activation.ts:180
fs.rmSync(binaryBackup, { force: true });
fs.rmSync(manifestBackup, { force: true });
if (fs.existsSync(binary)) fs.copyFileSync(binary, binaryBackup);
if (fs.existsSync(manifest)) fs.copyFileSync(manifest, manifestBackup);
const installed = await installProxy({ version, log });
const effective = await launchAndVerify(installed.binaryPath, installed.version, wait);
return { ...installed, pid: effective.pid };
} catch (error) {
const failure = error instanceof Error ? error.message : String(error);
if (fs.existsSync(binaryBackup)) {
try {
await stopEffective(wait);
fs.rmSync(binary, { force: true });
fs.renameSync(binaryBackup, binary);
fs.rmSync(manifest, { force: true });
if (fs.existsSync(manifestBackup)) fs.renameSync(manifestBackup, manifest);
if (prior) await launchAndVerify(prior.executable === binary ? binary : prior.executable, prior.version, wait);
} catch (rollbackError) {
throw new Error(`${failure} Rollback failed: ${rollbackError instanceof Error ? rollbackError.message : String(rollbackError)}`);
}
throw new Error(`${failure} Previous Meta-Proxy ${prior ? 'was restored and verified' : 'binary was restored; it was not running before the upgrade'}.`);
}
throw error;
} finally {
fs.rmSync(binaryBackup, { force: true });
fs.rmSync(manifestBackup, { force: true });
release?.();
}
}
View on GitHub (pinned to 29f048fc3b)
Solutions
- Read both messages in the error: the first clause is why the upgrade failed, the 'Rollback failed' clause is why restore failed — fix the rollback cause first (often relaunch timeout)
- Manually restore: move <binary>.rollback back over the binary (and manifest if present), then start meta-proxy by hand and verify /version
- Check the daemon log (proxyLogFilePath()) and free resources (disk space, file locks) before retrying the install
- On Windows, close processes holding meta-proxy.exe (tasklist /m, or a reboot) so the rename can succeed, then retry
Example fix
// manual recovery after rollback failure mv ~/.metaharness/bin/meta-proxy.rollback ~/.metaharness/bin/meta-proxy ~/.metaharness/bin/meta-proxy &
Defensive patterns
Strategy: try-catch
Validate before calling
// Snapshot state so you can recover manually if rollback itself fails
import { createHash } from 'node:crypto';
const bin = proxyBinaryPath();
const sha = fs.existsSync(bin) ? createHash('sha256').update(fs.readFileSync(bin)).digest('hex') : null;
fs.writeFileSync('/tmp/meta-proxy-preupgrade.json', JSON.stringify({ bin, sha, ts: Date.now() })); Type guard
null
Try / catch
try {
await installAndActivateProxy(version);
} catch (e) {
if (e instanceof Error && e.message.includes('Rollback failed')) {
// both causes are embedded: root failure + rollback failure; recover manually
console.error(e.message);
console.error(`Manually restore ${proxyBinaryPath()}.rollback if present`);
} else throw e;
} Prevention
- Ensure free disk space and no external file locks (esp. Windows) before upgrading
- Stop supervisors from holding/replacing the binary during the upgrade window
- Take your own backup of the binary/manifest as a second line of defense
- Fix the root-cause class (startup failures, network) first — rollback fails for the same environmental reasons
When it happens
Trigger: An install failure occurs with a backup present (e.g. launchAndVerify of the new version failed), and then rollback also fails — commonly the relaunch of the prior daemon times out (prior exit didn't complete / port busy), or file restore fails (EBUSY/EPERM on Windows, read-only filesystem).
Common situations: Old daemon can't restart because its binary was partially replaced; Windows file locks prevent rename while a process holds the .exe; disk full during restore; the pre-upgrade daemon can't come back up for the same environmental reasons the new one failed (config, permissions, supervisor interference).
Related errors
- ${failure} Previous Meta-Proxy ${prior ? 'was restored and v
- tar extraction failed (exit ${result.exitCode}): ${result.st
- Expand-Archive failed (exit ${result.exitCode}): ${result.st
- zip extraction failed via both available extractors. Expand-
- archive did not contain the expected binary at its root: ${b
AI-assisted analysis of ruvnet/ruflo@29f048fc3b (2026-09-01).
Data as JSON: /api/errors/6e35a4b9fca6eea4.
Report an issue: GitHub.