overleaf/overleaf · error
Conflict between billing info and account fields, but no sub
Error message
Conflict between billing info and account fields, but no subscription found to determine collection method
What it means
When migrating a customer, the code compares billingInfo fields (name, address, company, VAT) against account-level fields. If they conflict, the correct value depends on the subscription's collection method (automatic = prefer billing info; manual = prefer account fields). This error is thrown when there is a conflict but fetchCollectionMethod() returns null — no subscription exists to disambiguate which source wins, so the migration cannot proceed safely.
Source
Thrown at services/web/scripts/helpers/migrate_recurly_customers_to_stripe.helpers.mjs:1324
let name,
address,
companyName,
vatNumber,
collectionMethod,
billingInfoForPaymentMethod
if (!hasConflict) {
name = billingName ?? accountName
address = billingAddress ?? accountAddress
companyName = billingCompany ?? accountCompany
vatNumber = billingVat ?? accountVat
collectionMethod = null
billingInfoForPaymentMethod = null
} else {
collectionMethod = await fetchCollectionMethod()
if (!collectionMethod) {
throw new Error(
'Conflict between billing info and account fields, but no subscription found to determine collection method'
)
}
if (collectionMethod === 'automatic') {
name = billingName ?? accountName
address = billingAddress ?? accountAddress
companyName = billingCompany ?? accountCompany
vatNumber = billingVat ?? accountVat
billingInfoForPaymentMethod = null
} else if (collectionMethod === 'manual') {
name = accountName ?? billingName
address = accountAddress ?? billingAddress
companyName = accountCompany ?? billingCompany
vatNumber = accountVat ?? billingVat
billingInfoForPaymentMethod = account.billingInfo
} else {
throw new Error(`Unexpected collectionMethod: ${collectionMethod}`)View on GitHub (pinned to 28ad3b03b7)
Solutions
- Reconcile the conflicting fields in Recurly (make billingInfo match the account record, or vice versa) so hasConflict is false, then re-run
- Extend fetchCollectionMethod to also look up canceled/paused/past_due subscriptions, or default to a documented fallback collection method when no subscription exists
- Skip these customers and export them to a report for manual resolution instead of throwing
- If the customer has no subscription, migrate with a sensible default (e.g. account fields) rather than requiring a collection method
Example fix
// before
collectionMethod = await fetchCollectionMethod()
if (!collectionMethod) throw new Error('Conflict between billing info and account fields, but no subscription found to determine collection method')
// after
collectionMethod = await fetchCollectionMethod()
if (!collectionMethod) {
logger.warn(`No subscription for conflicting customer; defaulting to account fields`)
collectionMethod = 'manual' // documented fallback: account fields win
} Defensive patterns
Strategy: validation
Validate before calling
function conflictsResolvable(customer) {
return !customer.hasFieldConflict || customer.subscription != null
}
if (!conflictsResolvable(customerRecord)) {
manualReviewQueue.push(customerRecord.code)
} Type guard
function canDetermineCollectionMethod(customer) {
return !customer.hasFieldConflict ||
(customer.subscriptions?.data?.length > 0 &&
['automatic', 'manual'].includes(customer.subscriptions.data[0].collection_method))
} Try / catch
try {
result = await resolveBillingDetails(account, fetchCollectionMethod)
} catch (err) {
if (err.message.includes('no subscription found to determine collection method')) {
logger.warn({ accountId: account.code }, 'conflict without subscription; manual review')
addToManualReviewQueue(account.code)
return
}
throw err
} Prevention
- Run a pre-migration audit comparing billingInfo vs account fields and flag conflicts
- Broaden subscription lookups to include canceled/paused/past_due states before concluding none exists
- Keep Recurly account fields and billing info in sync via webhooks to avoid drift
- Exclude subscription-less customers from collection-method-dependent logic or define an explicit default
When it happens
Trigger: The customer has at least one conflict (nameConflict || addressConflict || companyConflict || vatConflict is true) AND the customer has no subscription in Recurly (or the subscription lookup fails), so await fetchCollectionMethod() resolves null and the throw executes.
Common situations: Canceled/expired customers whose subscriptions were deleted in Recurly but whose account and billing data still disagree; trial or future-dated customers with no active subscription yet; a subscription fetch filter (e.g. only 'active' state) that misses the customer's paused or past-due subscription; data entry errors where billing info was updated without updating the account record.
Related errors
- Field ${fieldName}: Primary and fallback values are both set
- batchedUpdate is already running
- project does not exist
- Subscription already has add-on
- Subscription does not have add-on to update
AI-assisted analysis of overleaf/overleaf@28ad3b03b7 (2026-09-03).
Data as JSON: /api/errors/37ea168b87e3b174.
Report an issue: GitHub.