{"record":{"id":"60fe01de12d3e37c","repo":"koala73/worldmonitor","slug":"company-monitoring-company-not-active","errorCode":null,"errorMessage":"COMPANY_MONITORING_COMPANY_NOT_ACTIVE","messagePattern":"COMPANY_MONITORING_COMPANY_NOT_ACTIVE","errorType":"exception","errorClass":"ConvexError","httpStatus":null,"severity":"error","filePath":"convex/companyMonitoring/orchestration.ts","lineNumber":322,"sourceCode":"        .unique(),\n      ctx.db\n        .query(\"companyMonitoringScanObligations\")\n        .withIndex(\"by_account_company_source\", (q) =>\n          q\n            .eq(\"ownerAccountId\", args.ownerAccountId)\n            .eq(\"companyId\", companyId)\n            .eq(\"source\", args.source),\n        )\n        .unique(),\n    ]);\n    return { companyId, company, obligation };\n  }));\n\n  if (\n    mode === \"strict\" &&\n    rows.some(({ company }) => !company || company.lifecycle !== \"active\")\n  ) {\n    throw new ConvexError(\"COMPANY_MONITORING_COMPANY_NOT_ACTIVE\");\n  }\n  const selectedRows = mode === \"strict\"\n    ? rows\n    : rows.filter(({ company, obligation }) =>\n      company?.lifecycle === \"active\" &&\n      (!obligation || obligation.state === \"cancelled\")\n    );\n  if (selectedRows.length === 0) return { status: \"replayed\" as const };\n  const companyIds = selectedRows.map(({ companyId }) => companyId);\n\n  const { windowStart, windowEnd } = scanWindowAt(now);\n  const queryVersion = QUERY_VERSION[args.source];\n  const cohortKey = await fingerprint({ version: \"cm-cohort-v1\", companyIds });\n  let workKey = await scanWorkKey({\n    ownerAccountId: args.ownerAccountId,\n    cohortKey,\n    source: args.source,\n    windowStart,","sourceCodeStart":304,"sourceCodeEnd":340,"githubUrl":"https://github.com/koala73/worldmonitor/blob/ffec79ac339946fd2d24e85845da5755dcaa534b/convex/companyMonitoring/orchestration.ts#L304-L340","documentation":"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.","triggerScenarios":"Calling scheduleAccountWorkHandler with mode 'strict' when at least one companyId does not exist or has lifecycle other than 'active' (paused/removed).","commonSituations":"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.","solutions":["Pre-filter the company list to lifecycle 'active' before scheduling in strict mode.","Switch to 'missing_only' mode if the caller wants best-effort scheduling that skips inactive companies.","Refresh company states immediately before assembling the strict cohort."],"exampleFix":"// before\nawait scheduleAccountWork(ctx, account, source, ids, \"strict\");\n\n// after\nconst activeIds = await filterActive(account, ids);\nif (activeIds.length === 0) return { status: \"no_active\" };\nawait scheduleAccountWork(ctx, account, source, activeIds, \"strict\");","handlingStrategy":"validation","validationCode":"const active = (await fetchCompanies(account, ids)).filter((c) => c?.lifecycle === \"active\");\nif (active.length !== ids.length) {\n  // use missing_only mode, or trim to active before strict scheduling\n}","typeGuard":"function allActive(rows: ({ lifecycle: string } | null)[]): boolean {\n  return rows.every((r) => r?.lifecycle === \"active\");\n}","tryCatchPattern":null,"preventionTips":["Pre-filter to active companies before strict scheduling.","Prefer missing_only mode for best-effort scheduling."],"tags":["convex","lifecycle","scheduling","company-monitoring"],"backgroundTag":null,"analyzedSha":"ffec79ac339946fd2d24e85845da5755dcaa534b","analyzedAt":"2026-08-12T11:24:56.012Z","schemaVersion":2},"datasetVersion":"2026-08-13T09:17:06.757Z"}