langfuse/langfuse · warning · TRPCError
CONFLICT
CONFLICT
Error message
error.message
What it means
CONFLICT TRPCError from the dashboardWidgets delete mutation (dashboardWidgets.ts:222). Deleting a widget that is still referenced by one or more dashboards causes the service to raise LangfuseConflictError, which is translated to a tRPC CONFLICT (HTTP 409) carrying the underlying error.message (e.g. 'Widget is still referenced in dashboards').
Source
Thrown at web/src/server/api/routers/dashboardWidgets.ts:222
)
.mutation(async ({ input, ctx }) => {
throwIfNoProjectAccess({
session: ctx.session,
projectId: input.projectId,
scope: "dashboards:CUD",
});
try {
// Delete the widget using the DashboardService
await DashboardService.deleteWidget(input.widgetId, input.projectId);
return {
success: true,
};
} catch (error) {
// If the widget is still referenced in dashboards, throw a CONFLICT error
if (error instanceof LangfuseConflictError) {
throw new TRPCError({
code: "CONFLICT",
message: error.message,
});
}
throw new TRPCError({
code: "INTERNAL_SERVER_ERROR",
message: (error as Error)?.message,
});
}
}),
});
View on GitHub (pinned to 59d92c7cf3)
Solutions
- Remove the widget from every dashboard that references it (edit each dashboard's widget list) before deleting it
- Use the API response to identify which dashboards still reference the widget, then unlink them
- If the UI should allow force-delete, first detach references in one transaction then delete the widget
- Catch CONFLICT client-side and prompt the user to unlink dashboards
Example fix
// before
await api.dashboardWidgets.delete.mutate({ projectId, widgetId });
// after
try {
await api.dashboardWidgets.delete.mutate({ projectId, widgetId });
} catch (e) {
if (e?.data?.code === 'CONFLICT') {
showUnlinkDashboardsPrompt(e.message);
return;
}
throw e;
} Defensive patterns
Strategy: try-catch
Validate before calling
const dashboards = await api.dashboards.list.query({ projectId });
const referencing = dashboards.filter((d) => d.widgets.some((w) => w.id === widgetId));
if (referencing.length > 0) throw new Error('unlink dashboards first'); Type guard
null
Try / catch
try {
await api.dashboardWidgets.delete.mutate({ projectId, widgetId });
} catch (e) {
if (e?.data?.code === 'CONFLICT') return promptUnlink(e.message);
throw e;
} Prevention
- Unlink a widget from all dashboards before deleting it
- Show referencing dashboards in the delete confirmation UI
- Handle 409 CONFLICT distinctly from 404/500 in clients
When it happens
Trigger: Calling the widget delete mutation while at least one dashboard row still includes this widget in its widgetIds/references; typical when a widget is shared across multiple dashboards or a dashboard was created from a template that cloned the reference.
Common situations: Shared KPI widgets reused on several dashboards; importing template dashboards that reference existing widgets; stale dashboard rows created before cascade cleanup was added.
Related errors
AI-assisted analysis of langfuse/langfuse@59d92c7cf3 (2026-08-27).
Data as JSON: /api/errors/5b72aca2b88a755f.
Report an issue: GitHub.