mastra-ai/mastra · error · Error
${config.integrationId} issue reconcile interval must be a p
Error message
${config.integrationId} issue reconcile interval must be a positive number. What it means
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.
Source
Thrown at mastracode/factory/src/integrations/issue-reconcile-worker.ts:42
readonly #intervalMs: number;
readonly #leaseTtlMs: number;
readonly #leaseKey: string;
readonly #leaseOwner = randomUUID();
#running = false;
#timer: ReturnType<typeof setTimeout> | undefined;
#inFlight: Promise<void> | undefined;
#leaseProvider: LeaseProvider = NoopLeaseProvider;
constructor(config: IssueReconcileWorkerConfig) {
super();
this.#integrationId = config.integrationId;
this.name = `${config.integrationId}-issue-reconcile`;
this.#leaseKey = `${config.integrationId}:issue-reconcile`;
this.#reconcile = config.reconcile;
this.#intervalMs = config.intervalMs ?? DEFAULT_ISSUE_RECONCILE_INTERVAL_MS;
if (!Number.isFinite(this.#intervalMs) || this.#intervalMs <= 0) {
throw new Error(`${config.integrationId} issue reconcile interval must be a positive number.`);
}
this.#leaseTtlMs = Math.max(MIN_LEASE_TTL_MS, this.#intervalMs * 3);
}
async init(deps: WorkerDeps): Promise<void> {
await super.init(deps);
this.#leaseProvider = getLeaseProvider(deps.pubsub);
}
async start(): Promise<void> {
if (this.#running) return;
if (!this.deps) throw new Error('IssueReconcileWorker: call init() before start()');
this.#running = true;
this.deps.logger.info(`${this.#integrationId} issue reconcile worker started`, { intervalMs: this.#intervalMs });
this.#schedule(0);
}
async stop(): Promise<void> {View on GitHub (pinned to 75dd419e61)
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
Example fix
// before
const worker = new IssueReconcileWorker({
integrationId: 'github',
reconcile,
intervalMs: Number(process.env.ISSUE_RECONCILE_INTERVAL_MS), // '' → 0 → throws
});
// after
const raw = Number(process.env.ISSUE_RECONCILE_INTERVAL_MS);
const intervalMs = Number.isFinite(raw) && raw > 0 ? raw : DEFAULT_ISSUE_RECONCILE_INTERVAL_MS;
const worker = new IssueReconcileWorker({ integrationId: 'github', reconcile, intervalMs }); Defensive patterns
Strategy: validation
Validate before calling
const raw = Number(config.intervalMs);
if (!Number.isFinite(raw) || raw <= 0) {
throw new Error(`intervalMs must be a positive finite number (got ${config.intervalMs})`);
}
const worker = new IssueReconcileWorker({ ...config, intervalMs: raw }); Type guard
function isPositiveFiniteMs(v: unknown): v is number {
return typeof v === 'number' && Number.isFinite(v) && v > 0;
} Try / catch
try {
worker = new IssueReconcileWorker(config);
} catch (err) {
if ((err as Error).message.includes('reconcile interval must be a positive number')) {
logger.error('Bad ISSUE_RECONCILE_INTERVAL_MS config, using default', { raw: config.intervalMs });
worker = new IssueReconcileWorker({ ...config, intervalMs: DEFAULT_ISSUE_RECONCILE_INTERVAL_MS });
} else throw err;
} Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Understand the failure class
Background: "Invalid value" and "allowed values are" config errors: what your library rejected and how to fix it — this error's family across 41 libraries.
Related errors
- terminationGraceMs must be greater than zero.
- Worker command must be a non-empty executable path.
- ${name} must be greater than zero.
- Unknown worker resource limit: ${name}.
- @mastra/livekit: set exactly one reply generator — `generate
AI-assisted analysis of mastra-ai/mastra@75dd419e61 (2026-08-30).
Data as JSON: /api/errors/58a9099290782886.
Report an issue: GitHub.