Summary
A Notification alert configured with resource = glossaryTerm and event-type filter = Thread Created / Thread Updated never fires. No notifications are delivered; the alert's Recent Events tab shows zero events; no error, log entry, or UI warning is surfaced.
The same pattern reproduces with other resource + event-type combinations that the backend cannot match. The alert builder UI lets users save such combinations as if they were valid.
Why the alert never matches
After the Task System Redesign (#25894), the three "thread sub-types" that historically lived inside Thread evolved into different shapes, with different change-event signatures:
| Sub-type |
Status |
Change-event entityType |
eventType values emitted |
| Task |
First-class entity |
task |
entityCreated / entityUpdated / entityDeleted |
| Announcement |
First-class entity |
announcement |
entityCreated / entityUpdated / entityDeleted |
| Conversation |
Remains Thread.type=Conversation |
THREAD |
threadCreated / threadUpdated / postCreated / postUpdated |
The backend resource gate in AlertUtil.shouldTriggerAlert (openmetadata-service/src/main/java/org/openmetadata/service/events/subscription/AlertUtil.java:137-166) handles thread events with this branch:
if (event.getEntityType().equals(THREAD)
&& (resource.equals("announcement")
|| resource.equals("task")
|| resource.equals("conversation"))) {
Thread thread = AlertsRuleEvaluator.getThread(event);
return resource.equalsIgnoreCase(thread.getType().value());
}
...
return config.getResources().contains(event.getEntityType());
A threadCreated event has entityType=THREAD. When the alert resource is glossaryTerm, neither this branch nor the fall-through getResources().contains(event.getEntityType()) matches. The event is dropped at the resource gate, before the user-configured filterByEventType is even evaluated. Nothing is recorded as a delivery attempt and nothing surfaces in Recent Events.
The UI is the source of the misleading experience: openmetadata-ui/src/main/resources/ui/src/utils/Alerts/AlertsUtil.tsx:1169-1182 populates the filterByEventType multiselect from the entire EventType enum (getSelectOptionsFromEnum(EventType)) regardless of which resource was selected at step 1. There is no per-resource restriction on the event types offered, so customers are presented with combinations that the gate cannot match.
Other unmatchable combinations from the same root cause
The same shape of mismatch occurs in additional combinations introduced by the Task redesign:
task + filterByEventType=[taskCreated] or [taskUpdated] — these EventType values are emitted by nothing in the current code base. The new Task entity emits entityCreated/entityUpdated like any other entity. Alerts filtering on taskCreated/taskUpdated never match.
task + filterByEventType=[taskResolved] or [taskClosed] — emitted only by the legacy /v1/feed/tasks/{id}/resolve|close routes, reachable today only via one governance workflow (Recognizer Feedback). New Task entity transitions do not emit them.
Task lifecycle transitions are silent
A related issue, surfaced during investigation: POST /api/v1/tasks/{id}/resolve and POST /api/v1/tasks/{id}/close produce zero change events. Verified empirically on 1.12.0-SNAPSHOT:
| Operation |
Endpoint |
Change-event emitted |
| Create |
POST /api/v1/tasks |
entityType=task, eventType=entityCreated |
| Patch |
PATCH /api/v1/tasks/{id} |
entityType=task, eventType=entityUpdated |
| Resolve (Open → Approved/Rejected/Completed) |
POST /api/v1/tasks/{id}/resolve |
none |
| Close (Open → Cancelled) |
POST /api/v1/tasks/{id}/close |
none |
| Delete |
DELETE /api/v1/tasks/{id} |
entityType=task, eventType=entityDeleted |
Mechanism: TaskResource.resolveTask (line 774) and closeTask (line 965) return Response.ok(resolvedTask).build() without setting CHANGE_CUSTOM_HEADER. The response interceptor ChangeEventHandler only emits a change event when that header is present (or when the status is CREATED), so the resolve/close turnaround yields nothing. The status mutation itself happens inside TaskWorkflowHandler via internal taskRepository.update(...) calls, which are not HTTP turnarounds and so never reach the interceptor either.
The semantically most meaningful Task transitions — resolution, closure, reopening — therefore produce no row in change_event, no audit-log entry, no notification delivery, no Recent Events tab entry, no webhook fire, no email. They are invisible to the entire downstream pipeline.
Steps to reproduce (the customer-reported case)
- Create a Notification alert with Resource =
Glossary Term.
- Add filter Event Type with values
Thread Created and Thread Updated.
- Add any destination (webhook/email/Slack).
- Create a glossary term and start a conversation on it. Optionally edit/resolve the thread.
Reproduction confirmation
Verified on 1.12.0-SNAPSHOT (60a2e6546e) with two side-by-side webhook subscriptions on the same conversation thread:
| Subscription |
Recent Events |
Webhook fired |
resource: conversation, no filters |
threadCreated, threadUpdated, postCreated |
✅ |
resource: glossaryTerm + filterByEventType: [threadCreated, threadUpdated] |
0 events |
❌ |
Independent verification of the entity model: creating a Task via POST /api/v1/tasks produces a single row in change_event with entityType=task, eventType=entityCreated; resolving and closing the same Task produce no further rows.
Reference
Internal discussion: https://collate-inc.slack.com/archives/C096NDJQAJW/p1777900803665159
Fix design: ALERTING_AFTER_TASK_REDESIGN.md
Summary
A Notification alert configured with resource =
glossaryTermand event-type filter =Thread Created/Thread Updatednever fires. No notifications are delivered; the alert's Recent Events tab shows zero events; no error, log entry, or UI warning is surfaced.The same pattern reproduces with other resource + event-type combinations that the backend cannot match. The alert builder UI lets users save such combinations as if they were valid.
Why the alert never matches
After the Task System Redesign (#25894), the three "thread sub-types" that historically lived inside
Threadevolved into different shapes, with different change-event signatures:entityTypeeventTypevalues emittedtaskentityCreated/entityUpdated/entityDeletedannouncemententityCreated/entityUpdated/entityDeletedThread.type=ConversationTHREADthreadCreated/threadUpdated/postCreated/postUpdatedThe backend resource gate in
AlertUtil.shouldTriggerAlert(openmetadata-service/src/main/java/org/openmetadata/service/events/subscription/AlertUtil.java:137-166) handles thread events with this branch:A
threadCreatedevent hasentityType=THREAD. When the alert resource isglossaryTerm, neither this branch nor the fall-throughgetResources().contains(event.getEntityType())matches. The event is dropped at the resource gate, before the user-configuredfilterByEventTypeis even evaluated. Nothing is recorded as a delivery attempt and nothing surfaces in Recent Events.The UI is the source of the misleading experience:
openmetadata-ui/src/main/resources/ui/src/utils/Alerts/AlertsUtil.tsx:1169-1182populates thefilterByEventTypemultiselect from the entireEventTypeenum (getSelectOptionsFromEnum(EventType)) regardless of which resource was selected at step 1. There is no per-resource restriction on the event types offered, so customers are presented with combinations that the gate cannot match.Other unmatchable combinations from the same root cause
The same shape of mismatch occurs in additional combinations introduced by the Task redesign:
task + filterByEventType=[taskCreated]or[taskUpdated]— theseEventTypevalues are emitted by nothing in the current code base. The new Task entity emitsentityCreated/entityUpdatedlike any other entity. Alerts filtering ontaskCreated/taskUpdatednever match.task + filterByEventType=[taskResolved]or[taskClosed]— emitted only by the legacy/v1/feed/tasks/{id}/resolve|closeroutes, reachable today only via one governance workflow (Recognizer Feedback). New Task entity transitions do not emit them.Task lifecycle transitions are silent
A related issue, surfaced during investigation:
POST /api/v1/tasks/{id}/resolveandPOST /api/v1/tasks/{id}/closeproduce zero change events. Verified empirically on1.12.0-SNAPSHOT:POST /api/v1/tasksentityType=task, eventType=entityCreatedPATCH /api/v1/tasks/{id}entityType=task, eventType=entityUpdatedPOST /api/v1/tasks/{id}/resolvePOST /api/v1/tasks/{id}/closeDELETE /api/v1/tasks/{id}entityType=task, eventType=entityDeletedMechanism:
TaskResource.resolveTask(line 774) andcloseTask(line 965) returnResponse.ok(resolvedTask).build()without settingCHANGE_CUSTOM_HEADER. The response interceptorChangeEventHandleronly emits a change event when that header is present (or when the status isCREATED), so the resolve/close turnaround yields nothing. The status mutation itself happens insideTaskWorkflowHandlervia internaltaskRepository.update(...)calls, which are not HTTP turnarounds and so never reach the interceptor either.The semantically most meaningful Task transitions — resolution, closure, reopening — therefore produce no row in
change_event, no audit-log entry, no notification delivery, no Recent Events tab entry, no webhook fire, no email. They are invisible to the entire downstream pipeline.Steps to reproduce (the customer-reported case)
Glossary Term.Thread CreatedandThread Updated.Reproduction confirmation
Verified on
1.12.0-SNAPSHOT (60a2e6546e)with two side-by-side webhook subscriptions on the same conversation thread:resource: conversation, no filtersthreadCreated,threadUpdated,postCreatedresource: glossaryTerm+filterByEventType: [threadCreated, threadUpdated]Independent verification of the entity model: creating a Task via
POST /api/v1/tasksproduces a single row inchange_eventwithentityType=task,eventType=entityCreated; resolving and closing the same Task produce no further rows.Reference
Internal discussion: https://collate-inc.slack.com/archives/C096NDJQAJW/p1777900803665159
Fix design: ALERTING_AFTER_TASK_REDESIGN.md