koala73/worldmonitor · critical · ConvexError

COMPANY_MONITORING_WORKER_UNAUTHORIZED

Error message

COMPANY_MONITORING_WORKER_UNAUTHORIZED

What it means

Thrown by requireWorkerSecret when the provided worker secret does not match the COMPANY_MONITORING_WORKER_SECRET environment variable (compared with a timing-safe SHA-256 comparison), or when that environment variable is unset/empty. This gates all worker-facing mutations so only trusted workers holding the secret can claim work or finalize results.

Source

Thrown at convex/companyMonitoring/orchestration.ts:211

async function timingSafeEqualStrings(left: string, right: string): Promise<boolean> {
  const encoder = new TextEncoder();
  const [leftDigest, rightDigest] = await Promise.all([
    crypto.subtle.digest("SHA-256", encoder.encode(left)),
    crypto.subtle.digest("SHA-256", encoder.encode(right)),
  ]);
  const leftBytes = new Uint8Array(leftDigest);
  const rightBytes = new Uint8Array(rightDigest);
  let mismatch = 0;
  for (let index = 0; index < leftBytes.length; index += 1) {
    mismatch |= leftBytes[index]! ^ rightBytes[index]!;
  }
  return mismatch === 0;
}

async function requireWorkerSecret(secret: string): Promise<void> {
  const expected = process.env.COMPANY_MONITORING_WORKER_SECRET ?? "";
  if (!expected || !(await timingSafeEqualStrings(secret, expected))) {
    throw new ConvexError("COMPANY_MONITORING_WORKER_UNAUTHORIZED");
  }
}

function providerRolloutEnabled(source: Source): boolean {
  const flags: Record<Source, boolean> = {
    exa: COMPANY_MONITORING_ROLLOUT_FLAGS.exaProvider,
    x: COMPANY_MONITORING_ROLLOUT_FLAGS.xProvider,
  };
  return flags[source];
}

function enabledSources(): Source[] {
  return (["exa", "x"] as const).filter(providerRolloutEnabled);
}

function requireProviderClaimPolicy(
  account: Doc<"companyMonitoringAccounts">,
  source: Source,

View on GitHub (pinned to ffec79ac33)

Solutions

  1. Set COMPANY_MONITORING_WORKER_SECRET in the Convex deployment environment to a strong shared value.
  2. Configure the worker to send the same secret and rotate both ends together.
  3. Verify the secret is present via the deployment dashboard (never log its value).

Example fix

// before — secret missing from Convex env, worker unauthorized

// after
# set in Convex deployment (do not commit the value)
npx convex env set COMPANY_MONITORING_WORKER_SECRET=<strong-random-secret>
# then configure the worker with the identical secret
Defensive patterns

Strategy: validation

Validate before calling

// ensure the env var is set and the worker sends the same secret
if (!process.env.COMPANY_MONITORING_WORKER_SECRET) {
  throw new Error("COMPANY_MONITORING_WORKER_SECRET not deployed");
}

Try / catch

try { await workerMutation(...); }
catch (err) {
  if (err instanceof ConvexError && err.message === "COMPANY_MONITORING_WORKER_UNAUTHORIZED") {
    // halt worker and alert; do not retry with the same secret
  } else throw err;
}

Prevention

When it happens

Trigger: Calling a worker-gated mutation without the secret, with the wrong secret, or when COMPANY_MONITORING_WORKER_SECRET is not configured in the Convex deployment.

Common situations: Secret not deployed to the Convex environment; worker using a stale secret after rotation; secret omitted from local dev config; secret leaked/mis-typed.

Understand the failure class

Related errors


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