koala73/worldmonitor · error · ConvexError
CUSTOMER_REFERENCE_CONFLICT
Error message
CUSTOMER_REFERENCE_CONFLICT
What it means
Thrown by updateCompanyForOwner when setting a customerReference that another active or paused company in the same account already uses. The duplicate check (findNoopByCustomerReference) queries the by_account_customerReference_lifecycle index for active then paused rows, and the conflict is reported only when the matched row is a different companyId than the one being patched.
Source
Thrown at convex/companyMonitoring/companies.ts:231
const hasName = Object.prototype.hasOwnProperty.call(patch, "name");
const hasDomicile = Object.prototype.hasOwnProperty.call(patch, "domicileCountry");
const hasCustomerReference = Object.prototype.hasOwnProperty.call(patch, "customerReference");
const normalizedFields = normalizeMonitoredCompanyInput({
name: hasName ? patch.name! : company.name,
domicileCountry: hasDomicile ? patch.domicileCountry! : company.domicileCountry,
customerReference: hasCustomerReference
? patch.customerReference
: company.customerReference,
});
if (hasCustomerReference && normalizedFields.customerReference) {
const conflict = await findNoopByCustomerReference(
ctx,
account.logicalAccountId,
normalizedFields.customerReference,
);
if (conflict && conflict.companyId !== company.companyId) {
throw new ConvexError("CUSTOMER_REFERENCE_CONFLICT");
}
}
const currentClaims = await ctx.db
.query("companyMonitoringClaims")
.withIndex("by_account_company", (q) =>
q.eq("ownerAccountId", account.logicalAccountId).eq("companyId", company.companyId),
)
.collect();
const currentById = new Map(currentClaims.map((claim) => [claim.claimId, claim]));
const removeIds = new Set(
removeClaimInputs.map((claimId) => assertLogicalId("claim", String(claimId))),
);
for (const claimId of removeIds) {
if (!currentById.has(claimId)) throw new ConvexError("CLAIM_NOT_FOUND");
}
if (hasCustomerReference && normalizedFields.customerReference !== company.customerReference) {
for (const claim of currentClaims) {View on GitHub (pinned to ffec79ac33)
Solutions
- Before patching, clear or change the customerReference on the company that currently owns it.
- Generate a unique customerReference per company rather than reusing one.
- If the reuse is intentional (the other company is no longer needed), set the other company to 'removed' first so findNoopByCustomerReference no longer matches it.
Example fix
// before
await update({ companyId: A, patch: { customerReference: "REF-1" } }); // REF-1 already on company B
// after
await setCompanyStateForOwner({ ownerUserId, companyId: B, state: "removed" });
// or pick a fresh reference
await update({ companyId: A, patch: { customerReference: "REF-2" } }); Defensive patterns
Strategy: validation
Validate before calling
// ensure the target customerReference is not used by another active/paused company
const owner = await listCompaniesForOwner(ownerUserId);
const taken = owner.some((c) => c.companyId !== companyId && c.customerReference === newRef);
if (taken) throw new Error("customerReference already in use"); Type guard
function isCustomerReferenceFree(rows: { companyId: string; customerReference?: string }[], companyId: string, ref: string): boolean {
return !rows.some((r) => r.companyId !== companyId && r.customerReference === ref);
} Try / catch
try { await updateCompanyForOwner(...); }
catch (err) {
if (err instanceof ConvexError && err.message === "CUSTOMER_REFERENCE_CONFLICT") {
// prompt user for a different reference
} else throw err;
} Prevention
- Generate customer references from a unique sequence per account.
- Clear a reference on the old owner before reassigning it.
When it happens
Trigger: Patching a company's customerReference to a value already assigned to a sibling company (active or paused) under the same owner account.
Common situations: Two companies sharing an internal billing/ERP reference; reassigning a reference without first clearing it from the previous company; importing companies with colliding references.
Related errors
- COMPANY_MONITORING_ACCESS_DENIED
- DUPLICATE_KEY
- [assignAndExportWave] waveLabel "${waveLabel}" already has s
- COMPANY_MONITORING_ACCESS_DENIED
- ACCOUNT_OWNER_FENCE_CONFLICT
AI-assisted analysis of koala73/worldmonitor@ffec79ac33 (2026-08-12).
Data as JSON: /api/errors/73029eb5c633e628.
Report an issue: GitHub.