Budibase/budibase · error
Notification ${notificationDocId} does not belong to escalat
Error message
Notification ${notificationDocId} does not belong to escalation ${escalationId} What it means
An anti-forgery check in the escalation respond flow: the notification document exists, but its escalationId field does not match the escalationId supplied in the request. This catches forged payloads that pair a valid notificationDocId with a different escalation to inject unauthorized responses. The mismatch is logged as a warning and the request is rejected.
Source
Thrown at packages/server/src/sdk/workspace/escalations.ts:184
return { status: "closed" }
}
const notifDoc = await db.tryGet<EscalationNotificationDoc>(notificationDocId)
if (!notifDoc) {
throw new Error(`Notification doc ${notificationDocId} not found`)
}
// Ensure the notification actually belongs to this escalation - stops a forged
// payload pairing a valid notificationDocId with a different escalationId.
if (notifDoc.escalationId !== escalationId) {
console.warn(
"Escalation respond: notification does not belong to escalation (possible forged payload)",
{
escalationId,
notificationDocId,
notifEscalationId: notifDoc.escalationId,
}
)
throw new Error(
`Notification ${notificationDocId} does not belong to escalation ${escalationId}`
)
}
await db.put({
...notifDoc,
response,
respondedAt: new Date().toISOString(),
})
const notifDocs = await listNotifications(escalationId)
const totalRecipients = contextDoc.recipients?.length ?? 0
const responses = notifDocs
.filter(doc => doc.respondedAt)
.sort((a, b) => (a.respondedAt! < b.respondedAt! ? -1 : 1))
.map(doc => doc.response)
console.log("Escalation respond: responses so far", {
escalationId,View on GitHub (pinned to a81a902e9a)
Solutions
- Send the escalationId and notificationDocId exactly as issued together in the original notification payload
- Audit client code that stores/pairs these IDs to ensure they are never combined across escalations
- If this appears in logs unexpectedly, treat it as a potential forged-request attempt and verify the source of the payloads
Example fix
// before await respond(otherEscalationId, response, resolve) // notifDoc.escalationId !== otherEscalationId // after await respond(notifDoc.escalationId, response, resolve) // use the escalation ID stored on the notification
Defensive patterns
Strategy: type-guard
Validate before calling
const notif = await db.tryGet<EscalationNotificationDoc>(notificationDocId)
if (notif && notif.escalationId !== escalationId) {
throw new Error("Notification/escalation mismatch — possible forged payload")
} Type guard
const belongsToEscalation = (
notif: EscalationNotificationDoc,
escalationId: string
): notif is EscalationNotificationDoc & { escalationId: string } =>
notif.escalationId === escalationId Try / catch
try {
await respond(escalationId, response, resolve)
} catch (err) {
if (/does not belong to escalation/.test(err.message)) {
console.warn("Rejecting mismatched escalation response")
return { status: "rejected" }
}
throw err
} Prevention
- Always send the exact escalationId/notificationDocId pair issued together
- Never mix IDs across escalations in bulk scripts
- Investigate mismatches as potential forged requests — the server logs them as warnings
When it happens
Trigger: Calling respond where notificationDocId points to a notification belonging to a different escalation — manually crafted requests mixing IDs from two escalations, or payloads reordered/merged incorrectly by client code.
Common situations: A malicious or buggy client replaying one escalation's notification ID against another escalation's ID; bulk scripts that zip two ID lists out of alignment.
Related errors
- Invalid object store key: path traversal is not allowed.
- Only HTTP(S) URLs are allowed.
- Only HTTP(S) URLs are allowed for query import
- Import url must not contain credentials
- File "${fileName}" has an invalid extension: "${extension}"
AI-assisted analysis of Budibase/budibase@a81a902e9a (2026-08-29).
Data as JSON: /api/errors/7037677150c586b9.
Report an issue: GitHub.