langfuse/langfuse · error
name_conflict
name_conflict
Error message
An evaluation rule named "${params.input.name}" already exists in this project. Use PATCH /api/public/unstable/evaluation-rules/${existing.id} to update it instead of creating a duplicate. What it means
409 name_conflict when creating an evaluation rule whose name already exists for an event/experiment target rule in the project. The message points to the PATCH endpoint of the existing rule.
Source
Thrown at web/src/features/evals/server/unstable-public-api/evaluation-rule-service.ts:324
input: PostUnstableEvaluationRuleBodyType;
evaluatorId?: string;
auditScope?: Pick<ApiAccessScope, "orgId" | "apiKeyId">;
}) {
// Scoped to the targets this API can write. Rule names carry no uniqueness constraint, so this
// only exists to hand back the id to PATCH instead of a second rule -- and PATCH 404s on the
// trace/dataset rules the backfill brought in, so including those would be a dead end.
const existing = await prisma.evaluationRule.findFirst({
where: {
projectId: params.projectId,
name: params.input.name,
targetObject: {
in: [EvalTargetObject.EVENT, EvalTargetObject.EXPERIMENT],
},
},
select: { id: true },
});
if (existing) {
throw createStructuredPublicApiError({
httpCode: 409,
code: "name_conflict",
message: `An evaluation rule named "${params.input.name}" already exists in this project. Use PATCH /api/public/unstable/evaluation-rules/${existing.id} to update it instead of creating a duplicate.`,
details: { field: "name" },
});
}
if (params.input.enabled) {
await assertActivePublicApiEvaluationRuleLimitNotExceeded(params.projectId);
}
await assertEvaluationRuleFilterValuesExistForProject({
projectId: params.projectId,
target: params.input.target,
filters: params.input.filter,
});
const requestedAssignments = getRequestedEvaluatorAssignments(params.input);
const evaluators = await Promise.all(
requestedAssignments.map(({ evaluator }, index) =>View on GitHub (pinned to 59d92c7cf3)
Solutions
- Use PATCH /api/public/unstable/evaluation-rules/{id} with the id from the error message instead of POST
- Pick a unique rule name
- Delete the existing rule first if it is obsolete
Example fix
// before
POST /api/public/unstable/evaluation-rules { name: "daily-eval", ... }
// after
PATCH /api/public/unstable/evaluation-rules/<existing.id> { ... } Defensive patterns
Strategy: validation
Validate before calling
const existing = await findRuleByName(name);
if (existing) return patchRule(existing.id, body);
await createRule({ ...body, name }); Try / catch
try { await createRule(body); } catch (e) { if (e?.error?.code === "name_conflict") { const id = e.error.message.match(/evaluation-rules\/([\w-]+)/)?.[1]; await patchRule(id, body); } else throw e; } Prevention
- Make create-by-name idempotent: look up before create
- Derive rule names deterministically so duplicates are detectable
When it happens
Trigger: POST /api/public/unstable/evaluation-rules with a name that matches an existing EVENT/EXPERIMENT-target rule in the same project.
Common situations: Re-running setup scripts that create rules idempotently-by-name; migrating configs between environments.
Related errors
AI-assisted analysis of langfuse/langfuse@59d92c7cf3 (2026-08-27).
Data as JSON: /api/errors/ddb5426694f25751.
Report an issue: GitHub.