{"record":{"id":"c8882909ae78ce1b","repo":"koala73/worldmonitor","slug":"invalid-company-monitoring-worker-id","errorCode":null,"errorMessage":"INVALID_COMPANY_MONITORING_WORKER_ID","messagePattern":"INVALID_COMPANY_MONITORING_WORKER_ID","errorType":"exception","errorClass":"ConvexError","httpStatus":null,"severity":"error","filePath":"convex/companyMonitoring/orchestration.ts","lineNumber":188,"sourceCode":"function scanWindowAt(timestamp: number) {\n  const windowEnd = Math.floor(timestamp / WINDOW_BUCKET_MS) * WINDOW_BUCKET_MS;\n  return { windowStart: windowEnd - WINDOW_MS, windowEnd };\n}\n\nasync function scanWorkKey(args: {\n  ownerAccountId: string;\n  cohortKey: string;\n  source: Source;\n  windowStart: number;\n  windowEnd: number;\n  queryVersion: string;\n}) {\n  return fingerprint({ version: \"cm-work-v1\", ...args });\n}\n\nfunction normalizeWorkerId(workerId: string): string {\n  if (!WORKER_ID.test(workerId)) {\n    throw new ConvexError(\"INVALID_COMPANY_MONITORING_WORKER_ID\");\n  }\n  return workerId;\n}\n\nasync function timingSafeEqualStrings(left: string, right: string): Promise<boolean> {\n  const encoder = new TextEncoder();\n  const [leftDigest, rightDigest] = await Promise.all([\n    crypto.subtle.digest(\"SHA-256\", encoder.encode(left)),\n    crypto.subtle.digest(\"SHA-256\", encoder.encode(right)),\n  ]);\n  const leftBytes = new Uint8Array(leftDigest);\n  const rightBytes = new Uint8Array(rightDigest);\n  let mismatch = 0;\n  for (let index = 0; index < leftBytes.length; index += 1) {\n    mismatch |= leftBytes[index]! ^ rightBytes[index]!;\n  }\n  return mismatch === 0;\n}","sourceCodeStart":170,"sourceCodeEnd":206,"githubUrl":"https://github.com/koala73/worldmonitor/blob/ffec79ac339946fd2d24e85845da5755dcaa534b/convex/companyMonitoring/orchestration.ts#L170-L206","documentation":"Thrown by normalizeWorkerId in orchestration.ts when the supplied workerId does not match the regex /^[A-Za-z0-9._:-]{1,64}$/. Worker ids are used as lease owners and audit identifiers, so they must be short, printable, and deterministic; malformed ids are rejected before any work is claimed.","triggerScenarios":"Calling a worker-facing mutation (e.g., claimNextWork) with a workerId containing characters outside [A-Za-z0-9._:-] or longer than 64 characters.","commonSituations":"Worker not setting its id; embedding a UUID with disallowed characters; appending a timestamp/hostname that exceeds 64 chars; passing an empty string.","solutions":["Configure the worker with a stable id matching the allowed character set and length.","Validate workerId against the regex client-side before the first call.","Generate ids from a known-safe alphabet (e.g., base32/base64url trimmed to 64)."],"exampleFix":"// before\nconst workerId = `${hostname}:${process.ppid}:${Date.now()}`; // may exceed 64 or use bad chars\n\n// after\nconst workerId = sanitizeWorkerId(`${hostname}-${process.ppid}`);\nif (!/^[A-Za-z0-9._:-]{1,64}$/.test(workerId)) throw new Error(\"bad worker id\");","handlingStrategy":"validation","validationCode":"const WORKER_ID = /^[A-Za-z0-9._:-]{1,64}$/;\nif (!WORKER_ID.test(workerId)) throw new Error(\"invalid worker id\");","typeGuard":"function isValidWorkerId(id: string): boolean {\n  return /^[A-Za-z0-9._:-]{1,64}$/.test(id);\n}","tryCatchPattern":null,"preventionTips":["Generate worker ids from a safe alphabet and cap length at 64.","Validate the id once at worker startup, not per call."],"tags":["convex","validation","worker","orchestration","company-monitoring"],"backgroundTag":null,"analyzedSha":"ffec79ac339946fd2d24e85845da5755dcaa534b","analyzedAt":"2026-08-12T11:24:56.012Z","schemaVersion":2},"datasetVersion":"2026-08-13T09:17:06.757Z"}