koala73/worldmonitor · error · ConvexError

COMPANY_MONITORING_COMPANY_NOT_ACTIVE

Error message

COMPANY_MONITORING_COMPANY_NOT_ACTIVE

What it means

Thrown by scheduleAccountWorkHandler in 'strict' mode when any requested company is missing or not in the 'active' lifecycle. Strict mode requires every requested company to be active; use 'missing_only' mode to silently skip inactive companies instead.

Source

Thrown at convex/companyMonitoring/orchestration.ts:322

        .unique(),
      ctx.db
        .query("companyMonitoringScanObligations")
        .withIndex("by_account_company_source", (q) =>
          q
            .eq("ownerAccountId", args.ownerAccountId)
            .eq("companyId", companyId)
            .eq("source", args.source),
        )
        .unique(),
    ]);
    return { companyId, company, obligation };
  }));

  if (
    mode === "strict" &&
    rows.some(({ company }) => !company || company.lifecycle !== "active")
  ) {
    throw new ConvexError("COMPANY_MONITORING_COMPANY_NOT_ACTIVE");
  }
  const selectedRows = mode === "strict"
    ? rows
    : rows.filter(({ company, obligation }) =>
      company?.lifecycle === "active" &&
      (!obligation || obligation.state === "cancelled")
    );
  if (selectedRows.length === 0) return { status: "replayed" as const };
  const companyIds = selectedRows.map(({ companyId }) => companyId);

  const { windowStart, windowEnd } = scanWindowAt(now);
  const queryVersion = QUERY_VERSION[args.source];
  const cohortKey = await fingerprint({ version: "cm-cohort-v1", companyIds });
  let workKey = await scanWorkKey({
    ownerAccountId: args.ownerAccountId,
    cohortKey,
    source: args.source,
    windowStart,

View on GitHub (pinned to ffec79ac33)

Solutions

  1. Pre-filter the company list to lifecycle 'active' before scheduling in strict mode.
  2. Switch to 'missing_only' mode if the caller wants best-effort scheduling that skips inactive companies.
  3. Refresh company states immediately before assembling the strict cohort.

Example fix

// before
await scheduleAccountWork(ctx, account, source, ids, "strict");

// after
const activeIds = await filterActive(account, ids);
if (activeIds.length === 0) return { status: "no_active" };
await scheduleAccountWork(ctx, account, source, activeIds, "strict");
Defensive patterns

Strategy: validation

Validate before calling

const active = (await fetchCompanies(account, ids)).filter((c) => c?.lifecycle === "active");
if (active.length !== ids.length) {
  // use missing_only mode, or trim to active before strict scheduling
}

Type guard

function allActive(rows: ({ lifecycle: string } | null)[]): boolean {
  return rows.every((r) => r?.lifecycle === "active");
}

Prevention

When it happens

Trigger: Calling scheduleAccountWorkHandler with mode 'strict' when at least one companyId does not exist or has lifecycle other than 'active' (paused/removed).

Common situations: A cohort built from stale data includes a since-paused or removed company; mixing paused companies into an explicit scan request; concurrent lifecycle change between cohort assembly and scheduling.

Related errors


AI-assisted analysis of koala73/worldmonitor@ffec79ac33 (2026-08-12). Data as JSON: /api/errors/60fe01de12d3e37c. Report an issue: GitHub.