ruvnet/ruflo · error · PodTemplateValidationError

auditReadView.retentionDays must be ≥1

Error message

auditReadView.retentionDays must be ≥1

What it means

Thrown by validateAuditReadView() after requireNumber() parses auditReadView.retentionDays: the value must be >= 1. Zero-day retention is treated as invalid configuration (it would mean the auditor sees nothing), so the schema forces an explicit positive retention window.

Source

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

  if (scheduleHours < 1) {
    throw new PodTemplateValidationError('bench.scheduleHours must be ≥1', path);
  }
  return { name, description, successCriteria, scheduleHours };
}

function validateAuditReadView(item: unknown, path: string): PodAuditReadView {
  if (!isObject(item)) {
    throw new PodTemplateValidationError('auditReadView must be an object', path);
  }
  const includedEventTypes = requireArray(item, 'includedEventTypes', path, (s, sp) => {
    if (typeof s !== 'string' || s.length === 0) {
      throw new PodTemplateValidationError('includedEventTypes entries must be non-empty strings', sp);
    }
    return s;
  });
  const retentionDays = requireNumber(item, 'retentionDays', path);
  if (retentionDays < 1) {
    throw new PodTemplateValidationError('auditReadView.retentionDays must be ≥1', path);
  }
  return { includedEventTypes, retentionDays };
}

// POSIX cron — five or six space-separated fields. Permissive on field
// contents (digits, *, -, /, ,) — actual cron evaluation happens at schedule
// time. We only catch obviously malformed values here.
const CRON_RE = /^([\d*/,\-]+\s+){4,5}[\d*/,\-]+$/;

/**
 * Validate `json` and return a typed `PodTemplate`. Throws
 * `PodTemplateValidationError` with a JSON-pointer-style path on failure.
 *
 * Used by:
 *   - `business_pod_validate` MCP tool — returns the error verbatim
 *   - `pod-tick.mjs` — pre-flight check before any pod execution
 *   - any external schema-loader that wants typed templates
 */

View on GitHub (pinned to fa13ee4ad6)

Solutions

  1. Set retentionDays to the smallest acceptable positive integer (e.g. 1) if you want minimal retention
  2. If long retention was intended, use the explicit number of days (365, 2555, ...)
  3. Re-run business_pod_validate to confirm the template is now fully valid

Example fix

// before
"auditReadView": { "includedEventTypes": ["pod.started"], "retentionDays": 0 }
// after
"auditReadView": { "includedEventTypes": ["pod.started"], "retentionDays": 90 }
Defensive patterns

Strategy: try-catch

Validate before calling

if (typeof av?.retentionDays !== 'number' || av.retentionDays < 1) {
  throw new Error('set auditReadView.retentionDays to a positive day count');
}

Type guard

function isValidRetentionDays(v: unknown): boolean {
  return typeof v === 'number' && Number.isFinite(v) && v >= 1;
}

Try / catch

try { validatePodTemplate(json); } catch (err) {
  if (err instanceof PodTemplateValidationError && /retentionDays/.test(err.message)) {
    // clamp or prompt for a positive retention, then re-validate
  }
}

Prevention

When it happens

Trigger: A pod template with auditReadView.retentionDays set to 0 or a negative number. Non-numeric values fail earlier in requireNumber with a different message.

Common situations: Configs where 0 meant 'keep forever' or 'disabled' in a previous system; sign errors from spreadsheets (e.g. -90); expressing 'no audit retention' which this schema does not permit.

Understand the failure class

Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.

Related errors


AI-assisted analysis of ruvnet/ruflo@fa13ee4ad6 (2026-08-18). Data as JSON: /api/errors/e126e45be7b9db7a. Report an issue: GitHub.