Budibase/budibase · error · Error
Attachments must have both "url" and "filename" keys. You…
Error message
Attachments must have both "url" and "filename" keys. You have provided: ${providedKeys} What it means
normalizeSingleAttachment coerces automation attachment inputs into {url, filename} objects. If the input object has no url key (and no resolvable URL), an Error is thrown listing the keys that were actually provided, since both url and filename are required for attachment handling.
Solutions
- Ensure the attachment input object includes a url key pointing to an accessible file URL.
- Check the upstream step/binding that should supply the URL — fix the binding so it resolves at runtime.
- Provide the full {url, filename} shape from the previous step's output.
- If filenames differ, pass {url, filename} explicitly rather than relying on name/derivation.
Example fix
// before
attachments: [{ filename: "report.pdf" }]
// after
attachments: [{ url: "https://example.com/report.pdf", filename: "report.pdf" }] Defensive patterns
Strategy: validation
Validate before calling
const input = maybeAttachment
if (typeof input !== "object" || input === null || !("url" in input) || !(input as any).url) {
throw new Error(`Attachment requires a url; got keys: ${Object.keys(input ?? {}).join(", ")}`)
} Type guard
const isAttachment = (v: unknown): v is { url: string; filename?: string } =>
typeof v === "object" && v !== null && "url" in v && typeof (v as { url: unknown }).url === "string" && (v as { url: string }).url !== "" Try / catch
try {
await runAutomation(inputs)
} catch (e) {
if (/Attachments must have both/.test(e.message)) {
// inspect the binding that supplies the attachment url
} else throw e
} Prevention
- Always include url in attachment objects; add filename explicitly when possible.
- Test bindings that supply attachment URLs with sample data.
- Validate upstream step outputs include url before feeding attachment fields.
- Use storage upload steps that return both url and filename.
When it happens
Trigger: An automation step (e.g. send email or webhook) receives an attachment object missing url — e.g. {filename: "a.txt"}, an empty object, or a mapped field whose URL binding resolved to null/undefined.
Common situations: Bindings that resolve to empty values at runtime; users pasting attachment objects from other systems with different key names; storage upload step output shape changed so only filename is produced.
Understand the failure class
Background: "missing required argument" and "the following required arguments were not provided": what required-argument errors mean and how to fix them — this error's family across 20 libraries.
Related errors
- Automation ID is required to test a saved password
- Budibase bash automation failed: Args must be a JSON array…
- Cannot manually trigger automation
- Email trigger inputs are required
- IMAP password is required when connection details change
AI-assisted analysis of Budibase/budibase@a81a902e9a (2026-08-29).
Data as JSON: /api/errors/07bc04969b70e2f8.
Report an issue: GitHub.
Appendix: source
Thrown at packages/server/src/automations/automationUtils.ts:158
}
}
function normalizeSingleAttachment(
input: string | AutomationAttachment
): AutomationAttachment | null {
if (typeof input === "string") {
try {
const parsed = JSON.parse(input)
return normalizeSingleAttachment(parsed)
} catch {
return { url: input, filename: deriveFilenameFromUrl(input) }
}
}
const url: string | undefined = input.url
if (!url) {
const providedKeys = Object.keys(input).join(", ")
throw new Error(
`Attachments must have both "url" and "filename" keys. You have provided: ${providedKeys}`
)
}
const filename: string =
input.filename ?? input.name ?? deriveFilenameFromUrl(url)
return { url, filename }
}
function normalizeAttachmentValue(
value: string | AutomationAttachment | AutomationAttachment[]
): AutomationAttachment | AutomationAttachment[] | null {
if (value == null) return null
if (typeof value === "string") {
try {
const parsed = JSON.parse(value)
return normalizeAttachmentValue(parsed)View on GitHub (pinned to a81a902e9a)