koala73/worldmonitor · error · ConvexError

COMPANY_LIMIT_REACHED

COMPANY_LIMIT_REACHED

Error message

COMPANY_LIMIT_REACHED

What it means

Thrown by createCompanyForOwner (convex/companyMonitoring/companies.ts:137) when the account's companyCount has reached its limit — account.companyLimit if set, otherwise the default COMPANY_LIMIT. Adding another monitored company is refused before any insert happens.

Solutions

  1. Surface an upgrade-path message to the user (raise account.companyLimit) or have them remove companies to free slots
  2. Check the count before submitting: query the account's companyCount/companyLimit and block the UI action early
  3. For imports, pre-compute how many slots remain and stop or chunk the batch accordingly
  4. If count looks wrong, verify that removals actually decrement companyCount (the patch does companyCount + 1 on insert, so the inverse must run on removal)

Example fix

// before
await api.companyMonitoring.createCompanyForOwner({ ownerUserId, clientRequestId, company });

// after
const account = await api.companyMonitoring.getAccount({ ownerUserId });
const limit = account.companyLimit ?? DEFAULT_COMPANY_LIMIT;
if ((account.companyCount ?? 0) >= limit) {
  throw new UserFacingError(`Company limit reached (${limit}). Remove a company or upgrade.`);
}
await api.companyMonitoring.createCompanyForOwner({ ownerUserId, clientRequestId, company });
Defensive patterns

Strategy: validation

Validate before calling

const account = await api.companyMonitoring.getAccount({ ownerUserId });
const limit = account.companyLimit ?? DEFAULT_COMPANY_LIMIT;
const count = account.companyCount ?? 0;
if (count >= limit) {
  throw new UserFacingError(`Company limit reached (${count}/${limit}). Remove a company or upgrade the plan.`);
}
await api.companyMonitoring.createCompanyForOwner({ ownerUserId, clientRequestId, company });

Try / catch

try {
  await api.companyMonitoring.createCompanyForOwner({ ownerUserId, clientRequestId, company });
} catch (err) {
  if (err instanceof ConvexError && err.data === "COMPANY_LIMIT_REACHED") {
    ui.showUpgradePrompt(); // or guide the user to remove companies
    return;
  }
  throw err;
}

Prevention

When it happens

Trigger: Calling add-company after the account already tracks the maximum number of companies; companyLimit was lowered (plan change) below the current companyCount, so even the next add fails; concurrent adds racing the companyCount check when the limit is nearly reached.

Common situations: Plan downgrade shrinking limits; bulk imports hitting the ceiling mid-batch; default limit surprise in staging with COMPANY_LIMIT lower than production expectations; count drift after failed deletes.

Related errors


AI-assisted analysis of koala73/worldmonitor@7d06c8633d (2026-08-21). Data as JSON: /api/errors/96d90b6330884cb4. Report an issue: GitHub.

Appendix: source

Thrown at convex/companyMonitoring/companies.ts:137

      )
      .unique();
    if (replay) {
      if (replay.directFingerprint !== directFingerprint) {
        throw new ConvexError("REPLAY_CONFLICT");
      }
      return { status: "replayed", companyId: replay.companyId };
    }

    const noop = await findNoopByCustomerReference(
      ctx,
      account.logicalAccountId,
      company.customerReference,
    );
    if (noop) return { status: "noop", companyId: noop.companyId };

    const companyCount = account.companyCount ?? 0;
    if (companyCount >= (account.companyLimit ?? COMPANY_LIMIT)) {
      throw new ConvexError("COMPANY_LIMIT_REACHED");
    }

    const companyId = await insertNormalizedCompany(ctx, account, company, {
      directRequestId: clientRequestId,
      directFingerprint,
    });
    await scheduleCompanySourcesHandler(ctx, {
      ownerAccountId: account.logicalAccountId,
      companyId,
    });
    await ctx.db.patch(account._id, {
      companyCount: companyCount + 1,
      snapshotGeneration: (account.snapshotGeneration ?? 0) + 1,
      updatedAt: Date.now(),
    });
    return { status: "created", companyId };
  },
});

View on GitHub (pinned to 7d06c8633d)