mastra-ai/mastra · error
GitHub issue reconcile interval must be a positive number.
Error message
GitHub issue reconcile interval must be a positive number.
What it means
The GitHub reconcile worker constructor validates that both the pull-request interval (intervalMs) and the derived issue interval (issueIntervalMs, defaulting to intervalMs) are finite numbers greater than zero. It throws this error when issueIntervalMs is missing its default, NaN, Infinity, zero, or negative, because a non-positive interval would make the issue reconciliation scheduler fire immediately or never, corrupting lease TTL math (#leaseTtlMs = min(intervals)*3).
Solutions
- Pass a finite positive number for intervalMs (and issueIntervalMs if set), e.g. 60_000.
- If relying on the default, omit issueIntervalMs entirely instead of passing null/0.
- Sanitize env/config parsing: `const ms = Number(process.env.X); if (!Number.isFinite(ms) || ms <= 0) use default;`.
- Catch the error at startup to fail fast with a clearer config-level message.
Example fix
// before
const worker = new GithubReconcileWorker({ intervalMs: Number(env.RECONCILE_MS) }); // NaN when env unset
// after
const ms = Number(env.RECONCILE_MS);
const worker = new GithubReconcileWorker({ intervalMs: Number.isFinite(ms) && ms > 0 ? ms : 60_000 }); Defensive patterns
Strategy: validation
Validate before calling
function validInterval(ms) { return typeof ms === 'number' && Number.isFinite(ms) && ms > 0; }
if (!validInterval(intervalMs) || (issueIntervalMs !== undefined && !validInterval(issueIntervalMs))) {
throw new TypeError('reconcile intervals must be finite positive numbers');
} Type guard
const isPositiveFinite = (v: unknown): v is number => typeof v === 'number' && Number.isFinite(v) && v > 0;
Try / catch
try {
worker = new GithubReconcileWorker(config);
} catch (err) {
if (err instanceof Error && err.message.includes('must be a positive number')) {
throw new Error(`Invalid reconcile config: ${JSON.stringify(config)}`, { cause: err });
}
throw err;
} Prevention
- Parse intervals through a single sanitize helper with a default fallback.
- Never pass user/env strings directly as intervalMs; coerce with Number and validate.
- Add a unit test asserting the constructor throws for 0, -1, and NaN.
When it happens
Trigger: Calling `new GithubReconcileWorker({ intervalMs: 0 })`, `intervalMs: -1000`, `intervalMs: NaN`, or explicitly passing `issueIntervalMs: 0` / `issueIntervalMs: -1` while intervalMs itself is valid (the PR-interval check passes but the issue check fails).
Common situations: Config loaded from env vars where GITHUB_ISSUE_RECONCILE_INTERVAL is unset-but-empty ('' parsed as invalid), a YAML/JSON config typo like `issueIntervalMs: -1`, or arithmetic that yields NaN (e.g. multiplying an undefined value) before constructing the worker.
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
- GitHub pull request reconcile interval must be a positive…
- must be a positive integer.
- Platform GitHub event polling interval must be a positive…
- Platform GitHub issue reconcile interval must be a positive…
- Platform GitHub pull request reconcile interval must be a…
AI-assisted analysis of mastra-ai/mastra@75dd419e61 (2026-08-30).
Data as JSON: /api/errors/627ce1291ce7739d.
Report an issue: GitHub.
Appendix: source
Thrown at mastracode/factory/src/integrations/github/reconcile-worker.ts:81
#leaseProvider: LeaseProvider = NoopLeaseProvider;
#nextPullRequestReconcileAt = 0;
#nextIssueReconcileAt = 0;
constructor(config: GithubReconcileWorkerConfig) {
super();
if (!config.reconcile && !config.reconcileIssues) {
throw new Error('GitHub reconcile worker requires a pull request or issue reconciler.');
}
this.#reconcile = config.reconcile;
this.#reconcileIssues = config.reconcileIssues;
this.#sourceControl = config.sourceControl;
this.#intervalMs = config.intervalMs ?? DEFAULT_GITHUB_RECONCILE_INTERVAL_MS;
this.#issueIntervalMs = config.issueIntervalMs ?? this.#intervalMs;
if (!Number.isFinite(this.#intervalMs) || this.#intervalMs <= 0) {
throw new Error('GitHub pull request reconcile interval must be a positive number.');
}
if (!Number.isFinite(this.#issueIntervalMs) || this.#issueIntervalMs <= 0) {
throw new Error('GitHub issue reconcile interval must be a positive number.');
}
this.#leaseTtlMs = Math.max(MIN_LEASE_TTL_MS, Math.min(this.#intervalMs, this.#issueIntervalMs) * 3);
this.#now = config.now ?? Date.now;
}
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('GithubReconcileWorker: call init() before start()');
this.#running = true;
this.deps.logger.info('GitHub reconcile worker started', {
pullRequestIntervalMs: this.#reconcile ? this.#intervalMs : undefined,
issueIntervalMs: this.#reconcileIssues ? this.#issueIntervalMs : undefined,
});View on GitHub (pinned to 75dd419e61)