refactor: fix all remaining inline error ternaries across 20 files

Used perl regex to replace all patterns of the form
  X instanceof Error ? X.message : String(X)
with getErrorMessage(X) for any variable name.

Added getErrorMessage imports to 6 files that lacked it.
Leaves only 2 intentional .stack || .message variants unchanged.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
Mikael Hugo 2026-05-11 14:50:01 +02:00
parent dac14043cd
commit aa6ecce384
18 changed files with 59 additions and 53 deletions

View file

@ -8,6 +8,7 @@ import {
} from "node:fs";
import { dirname } from "node:path";
import { isMainThread } from "node:worker_threads";
import { getErrorMessage } from "./error-utils.js";
const TRANSIENT_LOCK_ERROR_CODES = new Set(["EBUSY", "EPERM", "EACCES"]);
const MAX_RENAME_ATTEMPTS = 5;
@ -57,7 +58,7 @@ function buildAtomicWriteError(filePath, attempts, errors) {
const code = normalizeErrnoCode(lastError) ?? "UNKNOWN";
const messages = errors.map(
(e, i) =>
` attempt ${i + 1}: [${normalizeErrnoCode(e) ?? "UNKNOWN"}] ${e instanceof Error ? e.message : String(e)}`,
` attempt ${i + 1}: [${normalizeErrnoCode(e) ?? "UNKNOWN"}] ${getErrorMessage(e)}`,
);
const wrapped = new Error(
`Atomic write to ${filePath} failed after ${attempts} attempts:\n${messages.join("\n")}`,

View file

@ -540,7 +540,7 @@ export async function postUnitPreVerification(pctx, opts) {
s.lastGitActionStatus = "ok";
} catch (stageErr) {
const stageErrMsg =
stageErr instanceof Error ? stageErr.message : String(stageErr);
getErrorMessage(stageErr);
s.lastGitActionFailure = stageErrMsg;
s.lastGitActionStatus = "failed";
debugLog("postUnit", {
@ -653,7 +653,7 @@ export async function postUnitPreVerification(pctx, opts) {
}
}
} catch (e) {
const message = e instanceof Error ? e.message : String(e);
const message = getErrorMessage(e);
s.lastGitActionFailure = message;
s.lastGitActionStatus = "failed";
debugLog("postUnit", {
@ -1421,7 +1421,7 @@ export async function postUnitPostVerification(pctx) {
} catch (e) {
debugLog("postUnit", {
phase: "scaffold-keeper-dispatch",
error: e instanceof Error ? e.message : String(e),
error: getErrorMessage(e),
});
}
}

View file

@ -496,7 +496,7 @@ export function writeBlockerPlaceholder(unitType, unitId, base, reason) {
} catch (e) {
logWarning(
"recovery",
`updateTaskStatus failed during context exhaustion: ${e instanceof Error ? e.message : String(e)}`,
`updateTaskStatus failed during context exhaustion: ${getErrorMessage(e)}`,
);
}
// Append event so worktree reconciliation can replay this recovery completion
@ -511,7 +511,7 @@ export function writeBlockerPlaceholder(unitType, unitId, base, reason) {
} catch (e) {
logWarning(
"recovery",
`appendEvent failed for task recovery: ${e instanceof Error ? e.message : String(e)}`,
`appendEvent failed for task recovery: ${getErrorMessage(e)}`,
);
}
}
@ -521,7 +521,7 @@ export function writeBlockerPlaceholder(unitType, unitId, base, reason) {
} catch (e) {
logWarning(
"recovery",
`updateSliceStatus failed during context exhaustion: ${e instanceof Error ? e.message : String(e)}`,
`updateSliceStatus failed during context exhaustion: ${getErrorMessage(e)}`,
);
}
try {
@ -535,7 +535,7 @@ export function writeBlockerPlaceholder(unitType, unitId, base, reason) {
} catch (e) {
logWarning(
"recovery",
`appendEvent failed for slice recovery: ${e instanceof Error ? e.message : String(e)}`,
`appendEvent failed for slice recovery: ${getErrorMessage(e)}`,
);
}
}

View file

@ -275,7 +275,7 @@ export function auditOrphanedMilestoneBranches(basePath, isolationMode) {
// Not a registered worktree — expected for orphaned dirs
logWarning(
"engine",
`worktree remove failed (expected for orphaned dirs): ${e instanceof Error ? e.message : String(e)}`,
`worktree remove failed (expected for orphaned dirs): ${getErrorMessage(e)}`,
);
}
// If the directory still exists after git worktree remove (either it
@ -290,7 +290,7 @@ export function auditOrphanedMilestoneBranches(basePath, isolationMode) {
);
} catch (err2) {
warnings.push(
`Failed to remove worktree directory for ${milestoneId}: ${err2 instanceof Error ? err2.message : String(err2)}`,
`Failed to remove worktree directory for ${milestoneId}: ${getErrorMessage(err2)}`,
);
}
} else {
@ -1210,7 +1210,7 @@ export async function bootstrapAutoSession(
}
} catch (e) {
debugLog("git-lock-cleanup-failed", {
error: e instanceof Error ? e.message : String(e),
error: getErrorMessage(e),
});
}
// Pre-flight: validate milestone queue

View file

@ -788,7 +788,7 @@ export async function stopAuto(ctx, pi, reason) {
if (lockBase()) releaseSessionLock(lockBase());
} catch (e) {
debugLog("stop-cleanup-locks", {
error: e instanceof Error ? e.message : String(e),
error: getErrorMessage(e),
});
}
// ── Step 1b: Flush queued follow-up messages (#3512) ──
@ -801,7 +801,7 @@ export async function stopAuto(ctx, pi, reason) {
}
} catch (e) {
debugLog("stop-cleanup-queue", {
error: e instanceof Error ? e.message : String(e),
error: getErrorMessage(e),
});
}
// ── Step 2: Skill state ──
@ -810,7 +810,7 @@ export async function stopAuto(ctx, pi, reason) {
resetSkillTelemetry();
} catch (e) {
debugLog("stop-cleanup-skills", {
error: e instanceof Error ? e.message : String(e),
error: getErrorMessage(e),
});
}
// ── Step 3: SIGTERM handler ──
@ -818,7 +818,7 @@ export async function stopAuto(ctx, pi, reason) {
deregisterSigtermHandler();
} catch (e) {
debugLog("stop-cleanup-sigterm", {
error: e instanceof Error ? e.message : String(e),
error: getErrorMessage(e),
});
}
// ── Step 4: Auto-worktree exit ──
@ -885,7 +885,7 @@ export async function stopAuto(ctx, pi, reason) {
}
} catch (e) {
debugLog("stop-cleanup-worktree", {
error: e instanceof Error ? e.message : String(e),
error: getErrorMessage(e),
});
}
// ── Step 5: Rebuild state while DB is still open (#3599) ──
@ -898,7 +898,7 @@ export async function stopAuto(ctx, pi, reason) {
await rebuildState(s.basePath);
} catch (e) {
debugLog("stop-rebuild-state-failed", {
error: e instanceof Error ? e.message : String(e),
error: getErrorMessage(e),
});
}
}
@ -909,7 +909,7 @@ export async function stopAuto(ctx, pi, reason) {
closeDatabase();
} catch (e) {
debugLog("db-close-failed", {
error: e instanceof Error ? e.message : String(e),
error: getErrorMessage(e),
});
}
}
@ -930,7 +930,7 @@ export async function stopAuto(ctx, pi, reason) {
}
} catch (e) {
debugLog("stop-cleanup-basepath", {
error: e instanceof Error ? e.message : String(e),
error: getErrorMessage(e),
});
}
// ── Step 7b: Scaffold-keeper dispatch (ADR-021 Phase D) ──
@ -946,7 +946,7 @@ export async function stopAuto(ctx, pi, reason) {
}
} catch (e) {
debugLog("stop-cleanup-scaffold-keeper", {
error: e instanceof Error ? e.message : String(e),
error: getErrorMessage(e),
});
}
// ── Step 7c: Record-promoter dispatch (ADR-021 Phase D) ──
@ -962,7 +962,7 @@ export async function stopAuto(ctx, pi, reason) {
}
} catch (e) {
debugLog("stop-cleanup-record-promoter", {
error: e instanceof Error ? e.message : String(e),
error: getErrorMessage(e),
});
}
// ── Step 8: Ledger notification ──
@ -996,7 +996,7 @@ export async function stopAuto(ctx, pi, reason) {
}
} catch (e) {
debugLog("stop-cleanup-ledger", {
error: e instanceof Error ? e.message : String(e),
error: getErrorMessage(e),
});
}
// ── Step 9: Cmux sidebar / event log ──
@ -1009,7 +1009,7 @@ export async function stopAuto(ctx, pi, reason) {
);
} catch (e) {
debugLog("stop-cleanup-cmux", {
error: e instanceof Error ? e.message : String(e),
error: getErrorMessage(e),
});
}
// ── Step 10: Debug summary ──
@ -1025,7 +1025,7 @@ export async function stopAuto(ctx, pi, reason) {
}
} catch (e) {
debugLog("stop-cleanup-debug", {
error: e instanceof Error ? e.message : String(e),
error: getErrorMessage(e),
});
}
// ── Step 11: Reset metrics, routing, hooks ──
@ -1036,7 +1036,7 @@ export async function stopAuto(ctx, pi, reason) {
if (s.basePath) clearPersistedHookState(s.basePath);
} catch (e) {
debugLog("stop-cleanup-metrics", {
error: e instanceof Error ? e.message : String(e),
error: getErrorMessage(e),
});
}
// ── Step 12: Remove paused-session metadata (#1383) ──
@ -1066,7 +1066,7 @@ export async function stopAuto(ctx, pi, reason) {
}
} catch (e) {
debugLog("stop-cleanup-model", {
error: e instanceof Error ? e.message : String(e),
error: getErrorMessage(e),
});
}
// ── Step 14: Unblock pending unitPromise (#1799) ──
@ -1078,7 +1078,7 @@ export async function stopAuto(ctx, pi, reason) {
_resetPendingResolve();
} catch (e) {
debugLog("stop-cleanup-pending-resolve", {
error: e instanceof Error ? e.message : String(e),
error: getErrorMessage(e),
});
}
} finally {
@ -1181,7 +1181,7 @@ export async function pauseAuto(ctx, _pi, _errorContext) {
}
} catch (e) {
debugLog("pause-cleanup-queue", {
error: e instanceof Error ? e.message : String(e),
error: getErrorMessage(e),
});
}
// Unblock any pending unit promise so the auto-loop is not orphaned.
@ -1431,7 +1431,7 @@ async function runStartupDoctorFix(ctx, basePath) {
return report;
} catch (e) {
debugLog("startup-doctor-failed", {
error: e instanceof Error ? e.message : String(e),
error: getErrorMessage(e),
});
return null;
}
@ -1563,7 +1563,7 @@ export async function startAuto(ctx, pi, base, verboseMode, options) {
if (e.code !== "ENOENT") {
logWarning(
"session",
`pause file cleanup failed: ${e instanceof Error ? e.message : String(e)}`,
`pause file cleanup failed: ${getErrorMessage(e)}`,
{ file: "auto.ts" },
);
}
@ -1620,7 +1620,7 @@ export async function startAuto(ctx, pi, base, verboseMode, options) {
if (e.code !== "ENOENT") {
logWarning(
"session",
`pause file cleanup failed: ${e instanceof Error ? e.message : String(e)}`,
`pause file cleanup failed: ${getErrorMessage(e)}`,
{ file: "auto.ts" },
);
}
@ -1654,7 +1654,7 @@ export async function startAuto(ctx, pi, base, verboseMode, options) {
if (e.code !== "ENOENT") {
logWarning(
"session",
`stale pause file cleanup failed: ${e instanceof Error ? e.message : String(e)}`,
`stale pause file cleanup failed: ${getErrorMessage(e)}`,
{ file: "auto.ts" },
);
}
@ -1793,7 +1793,7 @@ export async function startAuto(ctx, pi, base, verboseMode, options) {
);
} catch (e) {
debugLog("resume-rebuild-state-failed", {
error: e instanceof Error ? e.message : String(e),
error: getErrorMessage(e),
});
}
try {
@ -1806,7 +1806,7 @@ export async function startAuto(ctx, pi, base, verboseMode, options) {
}
} catch (e) {
debugLog("resume-doctor-failed", {
error: e instanceof Error ? e.message : String(e),
error: getErrorMessage(e),
});
}
invalidateAllCaches();

View file

@ -12,6 +12,7 @@ import { join } from "node:path";
import { debugLog } from "../debug-logger.js";
import { formatDocSyncProposal, getDocSyncProposal } from "../doc-sync.js";
import { runGit } from "../git-service.js";
import { getErrorMessage } from "../error-utils.js";
/** Unit types that mutate code — doc-sync only runs after these. */
const CODE_MUTATING_UNITS = new Set(["execute-task", "complete-slice"]);
@ -80,7 +81,7 @@ export async function runDocSyncStagingCheck(basePath, unitType, ctx) {
} catch (e) {
debugLog("postUnit", {
phase: "doc-sync",
error: e instanceof Error ? e.message : String(e),
error: getErrorMessage(e),
});
}
}

View file

@ -1113,7 +1113,7 @@ export async function autoLoop(ctx, pi, s, deps) {
finishTurn("completed");
} catch (loopErr) {
// ── Blanket catch: absorb unexpected exceptions, apply graduated recovery ──
const msg = loopErr instanceof Error ? loopErr.message : String(loopErr);
const msg = getErrorMessage(loopErr);
debugLog("autoLoop", {
phase: "iteration-error",
message: msg,

View file

@ -731,7 +731,7 @@ export async function runPreDispatch(ic, loopState) {
error: String(mergeErr),
});
ctx.ui.notify(
`Merge failed: ${mergeErr instanceof Error ? mergeErr.message : String(mergeErr)}. Resolve and run /autonomous to resume.`,
`Merge failed: ${getErrorMessage(mergeErr)}. Resolve and run /autonomous to resume.`,
"error",
);
await deps.stopAuto(
@ -841,7 +841,7 @@ export async function runPreDispatch(ic, loopState) {
error: String(mergeErr),
});
ctx.ui.notify(
`Merge failed: ${mergeErr instanceof Error ? mergeErr.message : String(mergeErr)}. Resolve and run /autonomous to resume.`,
`Merge failed: ${getErrorMessage(mergeErr)}. Resolve and run /autonomous to resume.`,
"error",
);
await deps.stopAuto(
@ -977,7 +977,7 @@ export async function runPreDispatch(ic, loopState) {
error: String(mergeErr),
});
ctx.ui.notify(
`Merge failed: ${mergeErr instanceof Error ? mergeErr.message : String(mergeErr)}. Resolve and run /autonomous to resume.`,
`Merge failed: ${getErrorMessage(mergeErr)}. Resolve and run /autonomous to resume.`,
"error",
);
await deps.stopAuto(
@ -2049,7 +2049,7 @@ export async function runUnitPhase(ic, iterData, loopState, sidecarItem) {
});
} catch (solverErr) {
logWarning("engine", "Autonomous solver prompt injection failed", {
error: solverErr instanceof Error ? solverErr.message : String(solverErr),
error: getErrorMessage(solverErr),
});
}
s.lastPromptCharCount = finalPrompt.length;
@ -2081,7 +2081,7 @@ export async function runUnitPhase(ic, iterData, loopState, sidecarItem) {
finalPrompt = deps.reorderForCaching(finalPrompt);
} catch (reorderErr) {
const msg =
reorderErr instanceof Error ? reorderErr.message : String(reorderErr);
getErrorMessage(reorderErr);
logWarning("engine", "Prompt reorder failed", { error: msg });
}
// Select and apply model (with tier escalation on retry — normal units only)

View file

@ -27,6 +27,7 @@ import {
getCurrentTurnGeneration,
runWithTurnGeneration,
} from "./turn-epoch.js";
import { getErrorMessage } from "../error-utils.js";
// Tracks the latest session-switch attempt so a late timeout settlement from an
// older runUnit() call cannot clear the guard for a newer one.
@ -118,7 +119,7 @@ export async function runUnit(ctx, pi, s, unitType, unitId, prompt, options) {
} catch (sessionErr) {
if (sessionTimeoutHandle) clearTimeout(sessionTimeoutHandle);
const msg =
sessionErr instanceof Error ? sessionErr.message : String(sessionErr);
getErrorMessage(sessionErr);
debugLog("runUnit", {
phase: "session-error",
unitType,

View file

@ -183,7 +183,7 @@ async function runSessionStartupDoctorFix(ctx) {
);
}
} catch (error) {
const msg = error instanceof Error ? error.message : String(error);
const msg = getErrorMessage(error);
safetyLogWarning("startup-doctor", msg);
}
}

View file

@ -32,6 +32,7 @@ import {
supersedeMemory,
} from "./memory-store.js";
import { _getAdapter, isDbAvailable } from "./sf-db.js";
import { getErrorMessage } from "./error-utils.js";
function parseArgs(raw) {
const tokens = splitArgs(raw);
@ -533,7 +534,7 @@ function formatProbe(probe) {
return `${probe.ok ? "ok" : "not ok"} (${probe.status}${suffix})`;
}
function sanitizeProbeError(error) {
const message = error instanceof Error ? error.message : String(error);
const message = getErrorMessage(error);
return message.replace(/Bearer\s+[A-Za-z0-9._~+/=-]+/g, "Bearer [redacted]");
}
function handleExport(ctx, target) {

View file

@ -190,7 +190,7 @@ export async function handlePrBranch(args, ctx) {
gitAllowFail(basePath, ["cherry-pick", "--abort"]);
gitAllowFail(basePath, ["reset", "--hard", "HEAD"]);
const detail =
pickErr instanceof Error ? pickErr.message : String(pickErr);
getErrorMessage(pickErr);
ctx.ui.notify(
`Cherry-pick conflict at ${sha.slice(0, 8)}. Picked ${picked}/${commits.length} commits. Resolve manually.\n${detail}`,
"warning",

View file

@ -15,6 +15,7 @@
import { existsSync, readFileSync } from "node:fs";
import { join } from "node:path";
import { parse } from "yaml";
import { getErrorMessage } from "./error-utils.js";
// ─── Validation ──────────────────────────────────────────────────────────
/**
* Validate a parsed (but untyped) YAML object against the V1 workflow schema.
@ -290,7 +291,7 @@ export function loadDefinition(defsDir, name) {
try {
parsed = parse(raw);
} catch (e) {
const msg = e instanceof Error ? e.message : String(e);
const msg = getErrorMessage(e);
throw new Error(`Failed to parse YAML in ${filePath}: ${msg}`);
}
const { valid, errors } = validateDefinition(parsed);

View file

@ -1,4 +1,5 @@
import { importExtensionModule } from "@singularity-forge/coding-agent";
import { getErrorMessage } from "./error-utils.js";
export function registerExitCommand(pi, deps = {}) {
pi.registerCommand("exit", {
description: "Exit SF gracefully",
@ -14,7 +15,7 @@ export function registerExitCommand(pi, deps = {}) {
(await importExtensionModule(import.meta.url, "./auto.js")).stopAuto;
await stopAuto(ctx, pi, "Graceful exit");
} catch (e) {
const msg = e instanceof Error ? e.message : String(e);
const msg = getErrorMessage(e);
ctx.ui?.notify?.(
`Autonomous mode cleanup skipped (module version mismatch): ${msg}`,
"warning",

View file

@ -106,7 +106,7 @@ export function migrateToExternalState(basePath) {
} catch (copyErr) {
return {
migrated: false,
error: `Migration rename/copy failed: ${copyErr instanceof Error ? copyErr.message : String(copyErr)}`,
error: `Migration rename/copy failed: ${getErrorMessage(copyErr)}`,
};
}
} else {

View file

@ -1769,7 +1769,7 @@ function migrateSchema(db) {
// schema version permanently on read-only or full filesystems.
logWarning(
"db",
`Pre-migration backup failed: ${backupErr instanceof Error ? backupErr.message : String(backupErr)}`,
`Pre-migration backup failed: ${getErrorMessage(backupErr)}`,
);
}
}
@ -3401,7 +3401,7 @@ export function checkpointWal() {
} catch (e) {
logWarning(
"db",
`WAL checkpoint failed: ${e instanceof Error ? e.message : String(e)}`,
`WAL checkpoint failed: ${getErrorMessage(e)}`,
);
}
}

View file

@ -682,7 +682,7 @@ async function handleMerge(basePath, name, ctx, pi, targetBranch) {
return;
} catch (mergeErr) {
const mergeMsg =
mergeErr instanceof Error ? mergeErr.message : String(mergeErr);
getErrorMessage(mergeErr);
const isConflict = /conflict/i.test(mergeMsg);
if (isConflict) {
// Abort the failed merge so the working tree is clean for LLM retry

View file

@ -460,7 +460,7 @@ export function removeWorktree(basePath, name, opts = {}) {
} catch (e) {
logWarning(
"worktree",
`non-force worktree remove failed for ${gitReportedPath}: ${e instanceof Error ? e.message : String(e)}`,
`non-force worktree remove failed for ${gitReportedPath}: ${getErrorMessage(e)}`,
);
}
}
@ -637,7 +637,7 @@ export function removeWorktree(basePath, name, opts = {}) {
} catch (e) {
logWarning(
"worktree",
`non-force worktree remove failed for ${resolvedWtPath}: ${e instanceof Error ? e.message : String(e)}`,
`non-force worktree remove failed for ${resolvedWtPath}: ${getErrorMessage(e)}`,
);
}
}