Budibase/budibase · error · HTTPError
IMAP password is required
Error message
IMAP password is required
What it means
Automations with an email (IMAP) trigger store the password masked. hydrateAutomationSecrets detects a masked password (isMaskedPassword) and must restore the real stored password from the existing automation; it throws this 400 HTTPError when no existing automation exists or its trigger is not an email trigger, so there is no password to unmask.
Source
Thrown at packages/server/src/sdk/workspace/automations/crud.ts:380
if (!trigger || !isEmailTrigger(trigger) || !trigger.inputs) {
return automation
}
if (getEmailTriggerAuthType(trigger.inputs) === EmailTriggerAuthType.OAUTH2) {
const hydratedAutomation = cloneDeep(automation)
const hydratedTrigger = hydratedAutomation.definition?.trigger
if (isEmailTrigger(hydratedTrigger)) {
delete hydratedTrigger.inputs.password
}
return hydratedAutomation
}
if (!isMaskedPassword(trigger.inputs.password)) {
return automation
}
if (!existing || !isEmailTrigger(existing.definition?.trigger)) {
throw new HTTPError("IMAP password is required", 400)
}
const previousPassword = existing.definition.trigger.inputs?.password
if (!previousPassword) {
throw new HTTPError("IMAP password is required", 400)
}
const hydratedAutomation = cloneDeep(automation)
const hydratedTrigger = hydratedAutomation.definition?.trigger
if (!isEmailTrigger(hydratedTrigger) || !hydratedTrigger.inputs) {
throw new HTTPError("IMAP password is required", 400)
}
hydratedTrigger.inputs.password = previousPassword
return hydratedAutomation
}
function maskAutomationSecrets<T extends Automation>(automation: T): T {
const trigger = automation.definition?.triggerView on GitHub (pinned to a81a902e9a)
Solutions
- Provide the real (unmasked) IMAP password in trigger.inputs.password when creating a new automation or after changing the trigger type.
- Re-fetch the automation before editing so the trigger type matches and the masked password can be hydrated.
- If the trigger type changed, clear the password field and require the user to re-enter it.
Example fix
// before trigger.inputs.password = "****" // masked, but automation is new await update(automation) // after trigger.inputs.password = realImapPassword await update(automation)
Defensive patterns
Strategy: validation
Validate before calling
const isMasked = (p?: string) => !p || p === MASKED /* per isMaskedPassword */
if (isMasked(trigger.inputs?.password)) {
const existing = await sdk.automations.get(automation._id)
if (!existing || existing.definition?.trigger?.type !== trigger.type) {
// must send a real password
throw new Error("provide a real IMAP password")
}
}
await sdk.automations.update(automation) Try / catch
try {
await sdk.automations.update(automation)
} catch (e) {
if (e instanceof HTTPError && e.status === 400 && e.message === "IMAP password is required") {
// prompt the user to enter the IMAP password in plain text
}
throw e
} Prevention
- Require plain-text password entry for new automations and after trigger-type changes
- Re-fetch the automation before editing to keep trigger type in sync
- Don't round-trip masked values through clone/edit flows
When it happens
Trigger: create/update of an automation whose trigger.inputs.password is the masked placeholder, with either no existing automation for that _id, or the existing automation's definition.trigger failing isEmailTrigger.
Common situations: Client resubmits a masked password loaded from a GET response but the trigger type was switched (e.g. email -> webhook) before saving; creating a new automation by cloning a masked payload instead of entering a real password; stale client copy while another user changed the trigger type.
Related errors
- _id or _rev fields missing
- Field ${readonlyField} is readonly and it cannot be modified
- Automations cannot have more than ${MAX_STICKY_NOTES_PER_AUT
- automationId and appId are required
- Automation ID is required to test a saved password
AI-assisted analysis of Budibase/budibase@a81a902e9a (2026-08-29).
Data as JSON: /api/errors/72f6920602fb5e63.
Report an issue: GitHub.