langfuse/langfuse · error · LangfuseConflictError
buildTemplateInUseMessage(${names})
Error message
buildTemplateInUseMessage(${names}) What it means
Thrown as a LangfuseConflictError (409) when deleting an evaluator template that is still referenced by one or more evaluation rules. The message is built from the referencing rule names so users can see which rules block deletion. The service locks the evaluator row first, so the usage check is transactional.
Source
Thrown at web/src/features/evals/server/legacyCompatibilityService.ts:1487
const version = await tx.evaluatorVersion.findFirst({
where: { id: templateId, evaluator: { projectId } },
select: { evaluatorId: true },
});
if (!version) throw new LangfuseNotFoundError("Evaluator not found");
// Lock the evaluator so a rule cannot be assigned to it between the
// usage check and the delete.
await tx.$executeRaw`SELECT "id" FROM "evaluators" WHERE "id" = ${version.evaluatorId} AND "project_id" = ${projectId} FOR UPDATE`;
const referencingRules = await tx.evaluationRule.findMany({
where: {
projectId,
assignments: { some: { evaluatorId: version.evaluatorId } },
},
select: { name: true },
});
if (referencingRules.length > 0) {
throw new LangfuseConflictError(
buildTemplateInUseMessage(referencingRules.map(({ name }) => name)),
);
}
const versions = await tx.evaluatorVersion.findMany({
where: { evaluatorId: version.evaluatorId },
});
await tx.evaluator.delete({
where: { id: version.evaluatorId, projectId },
});
return versions;
});
}
}
View on GitHub (pinned to 59d92c7cf3)
Solutions
- Remove or re-point the evaluation rules named in the error message first, then retry deletion
- Use the rule update API to detach the evaluator assignment from each referencing rule
- Parse the rule names from the 409 message to drive a UI prompt offering to detach them
- If rules are unused, deactivate and delete them before deleting the template
Defensive patterns
Strategy: try-catch
Validate before calling
const referencing = await listRulesUsingTemplate(projectId, templateId);
if (referencing.length === 0) {
await svc.deleteTemplate(projectId, templateId);
} Type guard
function isConflictError(e: unknown): e is { name: 'LangfuseConflictError'; message: string } {
return e instanceof Error && (e as any).name === 'LangfuseConflictError';
} Try / catch
try {
await svc.deleteTemplate(projectId, templateId);
} catch (e) {
if (isConflictError(e)) {
// parse rule names from message, offer detach flow
const rules = parseRuleNames(e.message);
await detachEvaluatorFromRules(projectId, rules);
await svc.deleteTemplate(projectId, templateId);
return;
}
throw e;
} Prevention
- Check rule assignments before showing a delete button for templates
- Detach evaluators from rules as part of any template cleanup script
When it happens
Trigger: Calling deleteTemplate on a template while evaluation rules have assignments pointing to that template's evaluator; the referencingRules query inside the transaction returns one or more rule names.
Common situations: Trying to clean up old evaluator templates that are still attached to active or paused evaluation rules; bulk-deleting templates without first detaching them from rules.
Related errors
- Langfuse-managed evaluators cannot be deleted
- conflict
- conflict
- Evaluation rule not found after update
- Trace- and dataset-level evaluators are no longer available.
AI-assisted analysis of langfuse/langfuse@59d92c7cf3 (2026-08-27).
Data as JSON: /api/errors/5956580624e81398.
Report an issue: GitHub.