diff --git a/src/cron/delivery.ts b/src/cron/delivery.ts index 903abf8db5e..10f8b318d70 100644 --- a/src/cron/delivery.ts +++ b/src/cron/delivery.ts @@ -154,6 +154,9 @@ export function resolveFailureDestination( const jobAccountId = normalizeAccountId(jobFailureDest.accountId); const jobMode = normalizeFailureMode(jobFailureDest.mode); + // Track if 'to' was explicitly set at job level + const jobToExplicit = "to" in jobFailureDest && jobFailureDest.to !== undefined; + // Only override if explicitly set (not undefined) if (jobChannel !== undefined) { channel = jobChannel; @@ -167,7 +170,8 @@ export function resolveFailureDestination( if (jobMode !== undefined) { // Mode was explicitly overridden - clear inherited 'to' since URL semantics differ // between announce (channel recipient) and webhook (HTTP endpoint) - if (globalConfig?.mode !== jobMode) { + // But preserve explicit 'to' that was set at job level + if (!jobToExplicit && globalConfig?.mode !== jobMode) { to = undefined; } mode = jobMode; diff --git a/ui/src/ui/controllers/cron.ts b/ui/src/ui/controllers/cron.ts index 26682506347..0fc4a644cbe 100644 --- a/ui/src/ui/controllers/cron.ts +++ b/ui/src/ui/controllers/cron.ts @@ -608,8 +608,8 @@ function buildFailureAlert(form: CronFormState) { ...(cooldownMs !== undefined ? { cooldownMs } : {}), ...(accountId ? { accountId } : {}), }; - // Only include mode if explicitly set to non-default value - if (deliveryMode && deliveryMode !== "announce") { + // Always include mode so users can switch between webhook/announce + if (deliveryMode) { patch.mode = deliveryMode; } return patch;