{"record":{"id":"c49da4e0cc38a61d","repo":"koala73/worldmonitor","slug":"company-monitoring-access-denied","errorCode":"COMPANY_MONITORING_ACCESS_DENIED","errorMessage":"COMPANY_MONITORING_ACCESS_DENIED","messagePattern":"COMPANY_MONITORING_ACCESS_DENIED","errorType":"error_code","errorClass":"ConvexError","httpStatus":null,"severity":"error","filePath":"convex/apiKeys.ts","lineNumber":74,"sourceCode":"      .query(\"entitlements\")\n      .withIndex(\"by_userId\", (q) => q.eq(\"userId\", userId))\n      .first();\n    if (\n      !entitlement ||\n      entitlement.validUntil < Date.now() ||\n      !entitlement.features.apiAccess\n    ) {\n      throw new ConvexError(\"API_ACCESS_REQUIRED\");\n    }\n\n    const scopes = normalizeCompanyMonitoringScopes(args.scopes);\n    // Issuing a scoped key is a first-use entry point, so it provisions the\n    // root. Requesting no scopes must stay entirely off Company Monitoring.\n    const companyMonitoringAccount = scopes\n      ? await ensureActiveAccount(ctx, userId, entitlement)\n      : null;\n    if (scopes && !companyMonitoringAccount) {\n      throw new ConvexError(\"COMPANY_MONITORING_ACCESS_DENIED\");\n    }\n\n    if (!args.name.trim()) {\n      throw new ConvexError(\"INVALID_NAME\");\n    }\n    if (!/^wm_[a-f0-9]{5}$/.test(args.keyPrefix)) {\n      throw new ConvexError(\"INVALID_PREFIX\");\n    }\n    if (!/^[a-f0-9]{64}$/.test(args.keyHash)) {\n      throw new ConvexError(\"INVALID_HASH\");\n    }\n\n    // Enforce per-user key limit (count only non-revoked keys).\n    //\n    // API keys intentionally reject at the cap instead of silently rotating a\n    // valid key. If a prior race left too many active rows, converge by\n    // revoking enough oldest overflow rows to make room for this create.\n    const existing = await ctx.db","sourceCodeStart":56,"sourceCodeEnd":92,"githubUrl":"https://github.com/koala73/worldmonitor/blob/eeab0a219fce0f02a00603b532dbae9041b934ac/convex/apiKeys.ts#L56-L92","documentation":"Thrown when the caller requested Company Monitoring scopes but ensureActiveAccount could not provision or return an active companyMonitoringAccounts row for the user — the account is missing, not in the 'entitled' lifecycle, terminally tombstoned, or the entitlement check failed. Issuing a scoped key is a first-use provisioning entry point, so an active account must exist before a scoped key can bind to it.","triggerScenarios":"Thrown at convex/apiKeys.ts:74 when the library encounters an invalid state.","commonSituations":"See trigger scenarios.","solutions":["Retry key creation without scopes to decouple key issuance from Company Monitoring provisioning","Inspect the companyMonitoringAccounts row (lifecycle, terminalReason, ownerUserId) to see why no active account exists","Re-entitle or re-activate the Company Monitoring account, then request the scoped key again"],"exampleFix":null,"handlingStrategy":"validation","validationCode":null,"typeGuard":null,"tryCatchPattern":null,"preventionTips":[],"tags":[],"backgroundTag":null,"analyzedSha":"eeab0a219fce0f02a00603b532dbae9041b934ac","analyzedAt":"2026-08-21T16:51:25.751Z","contentChangedAt":"2026-08-21T16:51:25.751Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}