diff --git a/src/cron/isolated-agent/delivery-dispatch.ts b/src/cron/isolated-agent/delivery-dispatch.ts index ca5625da8de..a612fc1f65f 100644 --- a/src/cron/isolated-agent/delivery-dispatch.ts +++ b/src/cron/isolated-agent/delivery-dispatch.ts @@ -8,6 +8,7 @@ import { resolveMainSessionKey, } from "../../config/sessions/main-session.js"; import { sleepWithAbort } from "../../infra/backoff.js"; +import { formatErrorMessage } from "../../infra/errors.js"; import type { OutboundDeliveryResult } from "../../infra/outbound/deliver.js"; import { normalizeTargetForProvider } from "../../infra/outbound/target-normalization.js"; import { logWarn, logError } from "../../logger.js"; @@ -273,7 +274,7 @@ async function queueCronAwarenessSystemEvent(params: { }); } catch (err) { logWarn( - `[cron:${params.jobId}] failed to queue isolated cron awareness for the main session: ${err instanceof Error ? err.message : String(err)}`, + `[cron:${params.jobId}] failed to queue isolated cron awareness for the main session: ${formatErrorMessage(err)}`, ); } } @@ -488,7 +489,7 @@ export async function dispatchCronDelivery( ? (err: unknown, _payload: unknown) => { hadPartialFailure = true; logError( - `[cron:${params.job.id}] delivery payload failed (bestEffort): ${err instanceof Error ? err.message : String(err)}`, + `[cron:${params.job.id}] delivery payload failed (bestEffort): ${formatErrorMessage(err)}`, ); } : undefined; @@ -551,9 +552,7 @@ export async function dispatchCronDelivery( ...params.telemetry, }); } - logError( - `[cron:${params.job.id}] delivery failed (bestEffort): ${err instanceof Error ? err.message : String(err)}`, - ); + logError(`[cron:${params.job.id}] delivery failed (bestEffort): ${formatErrorMessage(err)}`); return null; } }; diff --git a/src/cron/isolated-agent/delivery-target.ts b/src/cron/isolated-agent/delivery-target.ts index 806f3d00900..681dc839f62 100644 --- a/src/cron/isolated-agent/delivery-target.ts +++ b/src/cron/isolated-agent/delivery-target.ts @@ -4,6 +4,7 @@ import type { OpenClawConfig } from "../../config/config.js"; import { resolveAgentMainSessionKey } from "../../config/sessions/main-session.js"; import { resolveStorePath } from "../../config/sessions/paths.js"; import { loadSessionStore } from "../../config/sessions/store-load.js"; +import { formatErrorMessage } from "../../infra/errors.js"; import { maybeResolveIdLikeTarget } from "../../infra/outbound/target-resolver.js"; import { tryResolveLoadedOutboundTarget } from "../../infra/outbound/targets-loaded.js"; import { resolveSessionDeliveryTarget } from "../../infra/outbound/targets-session.js"; @@ -106,7 +107,7 @@ export async function resolveDeliveryTarget( const selection = await resolveMessageChannelSelection({ cfg }); fallbackChannel = selection.channel; } catch (err) { - const detail = err instanceof Error ? err.message : String(err); + const detail = formatErrorMessage(err); channelResolutionError = new Error( `${detail} Set delivery.channel explicitly or use a main session with a previous channel.`, ); diff --git a/src/image-generation/runtime.ts b/src/image-generation/runtime.ts index 985bad44bf8..454a182538b 100644 --- a/src/image-generation/runtime.ts +++ b/src/image-generation/runtime.ts @@ -2,6 +2,7 @@ import type { AuthProfileStore } from "../agents/auth-profiles.js"; import { describeFailoverError, isFailoverError } from "../agents/failover-error.js"; import type { FallbackAttempt } from "../agents/model-fallback.types.js"; import type { OpenClawConfig } from "../config/config.js"; +import { formatErrorMessage } from "../infra/errors.js"; import { createSubsystemLogger } from "../logging/subsystem.js"; import { buildNoCapabilityModelConfiguredMessage, @@ -158,7 +159,7 @@ export async function generateImage( attempts.push({ provider: candidate.provider, model: candidate.model, - error: described?.message ?? (err instanceof Error ? err.message : String(err)), + error: described?.message ?? formatErrorMessage(err), reason: described?.reason, status: described?.status, code: described?.code, diff --git a/src/infra/exec-approval-channel-runtime.ts b/src/infra/exec-approval-channel-runtime.ts index bc4368cbde0..56c031461fc 100644 --- a/src/infra/exec-approval-channel-runtime.ts +++ b/src/infra/exec-approval-channel-runtime.ts @@ -3,6 +3,7 @@ import type { GatewayClient } from "../gateway/client.js"; import { createOperatorApprovalsGatewayClient } from "../gateway/operator-approvals-client.js"; import type { EventFrame } from "../gateway/protocol/index.js"; import { createSubsystemLogger } from "../logging/subsystem.js"; +import { formatErrorMessage } from "./errors.js"; import type { ExecApprovalRequest, ExecApprovalResolved } from "./exec-approvals.js"; import type { PluginApprovalRequest, PluginApprovalResolved } from "./plugin-approvals.js"; @@ -75,7 +76,7 @@ export function createExecApprovalChannelRuntime< const spawn = (label: string, promise: Promise): void => { void promise.catch((err: unknown) => { - const message = err instanceof Error ? err.message : String(err); + const message = formatErrorMessage(err); log.error(`${label}: ${message}`); }); }; diff --git a/src/infra/net/proxy-fetch.ts b/src/infra/net/proxy-fetch.ts index ece3f2df647..57b1c6004fa 100644 --- a/src/infra/net/proxy-fetch.ts +++ b/src/infra/net/proxy-fetch.ts @@ -1,5 +1,6 @@ import { EnvHttpProxyAgent, ProxyAgent, fetch as undiciFetch } from "undici"; import { logWarn } from "../../logger.js"; +import { formatErrorMessage } from "../errors.js"; import { hasEnvHttpProxyConfigured } from "./proxy-env.js"; export const PROXY_FETCH_PROXY_URL = Symbol.for("openclaw.proxyFetch.proxyUrl"); @@ -66,7 +67,7 @@ export function resolveProxyFetchFromEnv( }) as unknown as Promise) as typeof fetch; } catch (err) { logWarn( - `Proxy env var set but agent creation failed — falling back to direct fetch: ${err instanceof Error ? err.message : String(err)}`, + `Proxy env var set but agent creation failed — falling back to direct fetch: ${formatErrorMessage(err)}`, ); return undefined; } diff --git a/src/infra/push-apns.relay.ts b/src/infra/push-apns.relay.ts index 1b3251e6713..9af2400ac5e 100644 --- a/src/infra/push-apns.relay.ts +++ b/src/infra/push-apns.relay.ts @@ -5,6 +5,7 @@ import { signDevicePayload, type DeviceIdentity, } from "./device-identity.js"; +import { formatErrorMessage } from "./errors.js"; export type ApnsRelayPushType = "alert" | "background"; @@ -145,7 +146,7 @@ export function resolveApnsRelayConfigFromEnv( }, }; } catch (err) { - const message = err instanceof Error ? err.message : String(err); + const message = formatErrorMessage(err); return { ok: false, error: `invalid ${baseUrlSource} (${baseUrl}): ${message}`, diff --git a/src/infra/push-apns.ts b/src/infra/push-apns.ts index 6a281c9ec81..cb404e7e39f 100644 --- a/src/infra/push-apns.ts +++ b/src/infra/push-apns.ts @@ -4,6 +4,7 @@ import http2 from "node:http2"; import path from "node:path"; import { resolveStateDir } from "../config/paths.js"; import type { DeviceIdentity } from "./device-identity.js"; +import { formatErrorMessage } from "./errors.js"; import { createAsyncLock, readJsonFile, writeJsonAtomic } from "./json-files.js"; import { type ApnsRelayConfig, @@ -635,7 +636,7 @@ export async function resolveApnsAuthConfigFromEnv( }, }; } catch (err) { - const message = err instanceof Error ? err.message : String(err); + const message = formatErrorMessage(err); return { ok: false, error: `failed reading OPENCLAW_APNS_PRIVATE_KEY_PATH (${keyPath}): ${message}`, diff --git a/src/infra/windows-task-restart.ts b/src/infra/windows-task-restart.ts index 9cd139958b9..6bc2ed0b221 100644 --- a/src/infra/windows-task-restart.ts +++ b/src/infra/windows-task-restart.ts @@ -5,6 +5,7 @@ import path from "node:path"; import { quoteCmdScriptArg } from "../daemon/cmd-argv.js"; import { resolveGatewayWindowsTaskName } from "../daemon/constants.js"; import { resolveTaskScriptPath } from "../daemon/schtasks.js"; +import { formatErrorMessage } from "./errors.js"; import type { RestartAttempt } from "./restart.js"; import { resolvePreferredOpenClawTmpDir } from "./tmp-openclaw-dir.js"; @@ -78,7 +79,7 @@ export function relaunchGatewayScheduledTask(env: NodeJS.ProcessEnv = process.en return { ok: false, method: "schtasks", - detail: err instanceof Error ? err.message : String(err), + detail: formatErrorMessage(err), tried: [`schtasks /Run /TN "${taskName}"`], }; } diff --git a/src/music-generation/runtime.ts b/src/music-generation/runtime.ts index df519722730..17358247f1c 100644 --- a/src/music-generation/runtime.ts +++ b/src/music-generation/runtime.ts @@ -2,6 +2,7 @@ import type { AuthProfileStore } from "../agents/auth-profiles.js"; import { describeFailoverError, isFailoverError } from "../agents/failover-error.js"; import type { FallbackAttempt } from "../agents/model-fallback.types.js"; import type { OpenClawConfig } from "../config/config.js"; +import { formatErrorMessage } from "../infra/errors.js"; import { createSubsystemLogger } from "../logging/subsystem.js"; import { buildNoCapabilityModelConfiguredMessage, @@ -139,7 +140,7 @@ export async function generateMusic( attempts.push({ provider: candidate.provider, model: candidate.model, - error: described?.message ?? (err instanceof Error ? err.message : String(err)), + error: described?.message ?? formatErrorMessage(err), reason: described?.reason, status: described?.status, code: described?.code, diff --git a/src/plugin-sdk/run-command.ts b/src/plugin-sdk/run-command.ts index 7cf626ce8ef..9ff13034dd3 100644 --- a/src/plugin-sdk/run-command.ts +++ b/src/plugin-sdk/run-command.ts @@ -1,3 +1,4 @@ +import { formatErrorMessage } from "../infra/errors.js"; import { runCommandWithTimeout } from "../process/exec.js"; export type PluginCommandRunResult = { @@ -40,7 +41,7 @@ export async function runPluginCommandWithTimeout( return { code: 1, stdout: "", - stderr: error instanceof Error ? error.message : String(error), + stderr: formatErrorMessage(error), }; } } diff --git a/src/plugin-sdk/webhook-request-guards.ts b/src/plugin-sdk/webhook-request-guards.ts index d17bb2bf935..1b181247444 100644 --- a/src/plugin-sdk/webhook-request-guards.ts +++ b/src/plugin-sdk/webhook-request-guards.ts @@ -1,4 +1,5 @@ import type { IncomingMessage, ServerResponse } from "node:http"; +import { formatErrorMessage } from "../infra/errors.js"; import { installRequestBodyLimitGuard, isRequestBodyLimitError, @@ -268,8 +269,7 @@ export async function readWebhookBodyOrReject(params: { return respondWebhookBodyReadError({ res: params.res, code: "INVALID_BODY", - invalidMessage: - params.invalidBodyMessage ?? (error instanceof Error ? error.message : String(error)), + invalidMessage: params.invalidBodyMessage ?? formatErrorMessage(error), }); } } diff --git a/src/video-generation/runtime.ts b/src/video-generation/runtime.ts index 097baa03b09..3d58c7a63b3 100644 --- a/src/video-generation/runtime.ts +++ b/src/video-generation/runtime.ts @@ -2,6 +2,7 @@ import type { AuthProfileStore } from "../agents/auth-profiles.js"; import { describeFailoverError, isFailoverError } from "../agents/failover-error.js"; import type { FallbackAttempt } from "../agents/model-fallback.types.js"; import type { OpenClawConfig } from "../config/config.js"; +import { formatErrorMessage } from "../infra/errors.js"; import { createSubsystemLogger } from "../logging/subsystem.js"; import { buildNoCapabilityModelConfiguredMessage, @@ -182,7 +183,7 @@ export async function generateVideo( attempts.push({ provider: candidate.provider, model: candidate.model, - error: described?.message ?? (err instanceof Error ? err.message : String(err)), + error: described?.message ?? formatErrorMessage(err), reason: described?.reason, status: described?.status, code: described?.code,