{"record":{"id":"58a9099290782886","repo":"mastra-ai/mastra","slug":"config-integrationid-issue-reconcile-interval-m","errorCode":null,"errorMessage":"${config.integrationId} issue reconcile interval must be a positive number.","messagePattern":"(.+?) issue reconcile interval must be a positive number\\.","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"mastracode/factory/src/integrations/issue-reconcile-worker.ts","lineNumber":42,"sourceCode":"  readonly #intervalMs: number;\n  readonly #leaseTtlMs: number;\n  readonly #leaseKey: string;\n  readonly #leaseOwner = randomUUID();\n\n  #running = false;\n  #timer: ReturnType<typeof setTimeout> | undefined;\n  #inFlight: Promise<void> | undefined;\n  #leaseProvider: LeaseProvider = NoopLeaseProvider;\n\n  constructor(config: IssueReconcileWorkerConfig) {\n    super();\n    this.#integrationId = config.integrationId;\n    this.name = `${config.integrationId}-issue-reconcile`;\n    this.#leaseKey = `${config.integrationId}:issue-reconcile`;\n    this.#reconcile = config.reconcile;\n    this.#intervalMs = config.intervalMs ?? DEFAULT_ISSUE_RECONCILE_INTERVAL_MS;\n    if (!Number.isFinite(this.#intervalMs) || this.#intervalMs <= 0) {\n      throw new Error(`${config.integrationId} issue reconcile interval must be a positive number.`);\n    }\n    this.#leaseTtlMs = Math.max(MIN_LEASE_TTL_MS, this.#intervalMs * 3);\n  }\n\n  async init(deps: WorkerDeps): Promise<void> {\n    await super.init(deps);\n    this.#leaseProvider = getLeaseProvider(deps.pubsub);\n  }\n\n  async start(): Promise<void> {\n    if (this.#running) return;\n    if (!this.deps) throw new Error('IssueReconcileWorker: call init() before start()');\n    this.#running = true;\n    this.deps.logger.info(`${this.#integrationId} issue reconcile worker started`, { intervalMs: this.#intervalMs });\n    this.#schedule(0);\n  }\n\n  async stop(): Promise<void> {","sourceCodeStart":24,"sourceCodeEnd":60,"githubUrl":"https://github.com/mastra-ai/mastra/blob/75dd419e613fe9c39f846ffc500716141b74fda6/mastracode/factory/src/integrations/issue-reconcile-worker.ts#L24-L60","documentation":"The IssueReconcileWorker constructor validates its intervalMs configuration before the worker is scheduled. The interval must be a finite positive number since it drives setInterval-like scheduling and lease TTL derivation (leaseTtlMs = max(MIN_LEASE_TTL_MS, intervalMs * 3)). A zero, negative, NaN, or Infinity interval would break scheduling or lease expiry math, so construction fails immediately with the integration ID in the message.","triggerScenarios":"Constructing new IssueReconcileWorker({ integrationId, reconcile, intervalMs }) where intervalMs is 0, a negative number, NaN, or Infinity — usually because it came from parsed env config or a JSON config that was missing/invalid.","commonSituations":"Env var like ISSUE_RECONCILE_INTERVAL_MS parsed with Number('') → 0 or Number('abc') → NaN; config file has \"intervalMs\": null and the ?? fallback doesn't apply because null was explicitly set (note: nullish coalescing does catch null, but 0 passes through); unit mismatch (seconds given where ms expected → value like 30 treated as effectively zero-lease); copied default with 0 meaning 'disabled' which is not supported.","solutions":["Fix the config source so intervalMs is a positive finite number in milliseconds (e.g. 300000 for 5 minutes)","Sanitize at the config boundary: reject/replace non-finite or <= 0 values before constructing the worker","If the value comes from an env var, validate with Number.isFinite(v) && v > 0 and fall back to DEFAULT_ISSUE_RECONCILE_INTERVAL_MS","If 0 was intended to mean 'disabled', use an explicit enabled flag instead of encoding it in intervalMs"],"exampleFix":"// before\nconst worker = new IssueReconcileWorker({\n  integrationId: 'github',\n  reconcile,\n  intervalMs: Number(process.env.ISSUE_RECONCILE_INTERVAL_MS), // '' → 0 → throws\n});\n// after\nconst raw = Number(process.env.ISSUE_RECONCILE_INTERVAL_MS);\nconst intervalMs = Number.isFinite(raw) && raw > 0 ? raw : DEFAULT_ISSUE_RECONCILE_INTERVAL_MS;\nconst worker = new IssueReconcileWorker({ integrationId: 'github', reconcile, intervalMs });","handlingStrategy":"validation","validationCode":"const raw = Number(config.intervalMs);\nif (!Number.isFinite(raw) || raw <= 0) {\n  throw new Error(`intervalMs must be a positive finite number (got ${config.intervalMs})`);\n}\nconst worker = new IssueReconcileWorker({ ...config, intervalMs: raw });","typeGuard":"function isPositiveFiniteMs(v: unknown): v is number {\n  return typeof v === 'number' && Number.isFinite(v) && v > 0;\n}","tryCatchPattern":"try {\n  worker = new IssueReconcileWorker(config);\n} catch (err) {\n  if ((err as Error).message.includes('reconcile interval must be a positive number')) {\n    logger.error('Bad ISSUE_RECONCILE_INTERVAL_MS config, using default', { raw: config.intervalMs });\n    worker = new IssueReconcileWorker({ ...config, intervalMs: DEFAULT_ISSUE_RECONCILE_INTERVAL_MS });\n  } else throw err;\n}","preventionTips":["Validate interval config at the boundary (env/config file) before constructing workers","Remember empty-string env vars parse to 0 and garbage parses to NaN — guard both","Document intervalMs units (milliseconds) to avoid second/ms mismatches","Use an explicit enabled/disabled flag rather than encoding 'disabled' as intervalMs: 0"],"tags":["configuration","worker","validation"],"backgroundTag":"invalid-config-value","analyzedSha":"75dd419e613fe9c39f846ffc500716141b74fda6","analyzedAt":"2026-08-30T00:15:31.844Z","schemaVersion":2},"datasetVersion":"2026-08-30T03:17:51.788Z"}