ruvnet/ruflo · error · PodTemplateValidationError

reservationExpiryMs must be within [5000, 300000] ms (ADR-16

Error message

reservationExpiryMs must be within [5000, 300000] ms (ADR-164.1 §3.2)

What it means

Thrown by validatePodTemplate() when the optional 'reservationExpiryMs' field is present but outside the bounded range [5000, 300000] milliseconds (5 seconds to 5 minutes), per ADR-164.1 §3.2. This value controls the atomic budget tracker's reservation expiry. If the field is absent entirely, no error is thrown and a default of 60000 ms is used.

Source

Thrown at v3/@claude-flow/cli/src/business-pods/pod-schema.ts:256

      '/',
    );
  }
  const preferLocalExecution = requireBoolean(json, 'preferLocalExecution', '/');
  const cronSchedule = requireString(json, 'cronSchedule', '/');
  if (!CRON_RE.test(cronSchedule)) {
    throw new PodTemplateValidationError(
      'cronSchedule must be a POSIX cron expression (5 or 6 fields)',
      '/',
    );
  }
  const auditReadView = validateAuditReadView(json.auditReadView, '/auditReadView');

  let reservationExpiryMs: number | undefined;
  if (json.reservationExpiryMs !== undefined) {
    const v = requireNumber(json, 'reservationExpiryMs', '/');
    // ADR-164.1 §3.2 — bounded to [5_000, 300_000] ms.
    if (v < 5_000 || v > 300_000) {
      throw new PodTemplateValidationError(
        'reservationExpiryMs must be within [5000, 300000] ms (ADR-164.1 §3.2)',
        '/',
      );
    }
    reservationExpiryMs = v;
  }

  return {
    name,
    displayName,
    roomId,
    agents,
    allowedMcpTools,
    bench,
    piiPolicy: piiPolicy as PiiPolicy,
    budgetUsdMonthly,
    budgetUsdPerRun,
    preferLocalExecution,

View on GitHub (pinned to 6b01dc5a68)

Solutions

  1. Set reservationExpiryMs to a value between 5000 and 300000 (inclusive)
  2. Or remove the field entirely to use the default 60000 ms (60 seconds)
  3. Double-check the unit is milliseconds, not seconds

Example fix

// before
{ "reservationExpiryMs": 60 }

// after
{ "reservationExpiryMs": 60000 }
Defensive patterns

Strategy: validation

Validate before calling

const MIN_EXPIRY = 5000;
const MAX_EXPIRY = 300000;

if (template.reservationExpiryMs !== undefined) {
  if (template.reservationExpiryMs < MIN_EXPIRY || template.reservationExpiryMs > MAX_EXPIRY) {
    throw new Error(`reservationExpiryMs must be within [${MIN_EXPIRY}, ${MAX_EXPIRY}] ms`);
  }
}

Type guard

function isValidReservationExpiry(v: unknown): boolean {
  return v === undefined || (typeof v === 'number' && Number.isFinite(v) && v >= 5000 && v <= 300000);
}

Try / catch

try {
  validatePodTemplate(json);
} catch (e) {
  if (e instanceof PodTemplateValidationError && e.message.includes('reservationExpiryMs')) {
    // Remove the field to use default 60000ms, or set to [5000, 300000]
  }
}

Prevention

When it happens

Trigger: The pod-template JSON includes "reservationExpiryMs" with a value less than 5000 (e.g. 1000) or greater than 300000 (e.g. 600000). If the field is omitted entirely, this check is never reached.

Common situations: A value was set in milliseconds but intended as seconds (e.g. 60 meaning 60 seconds but interpreted as 60ms — below the 5000 floor); a value was copied from a different system with a different expiry window.

Related errors


AI-assisted analysis of ruvnet/ruflo@6b01dc5a68 (2026-08-12). Data as JSON: /api/errors/9b672140befca65a. Report an issue: GitHub.