affaan-m/ECC · error · Error

Invalid target version

Error message

Invalid target version: ${targetVersion}

What it means

rollbackTo converts targetVersion to a number and requires it to be a positive integer before rolling back. Versions are 1-based integers matching stored files v<n>.md, so non-integers, zero, negatives, and non-numeric input are all rejected. The original input is echoed in the message.

Solutions

  1. Pass a positive integer, e.g. rollbackTo(skillPath, 2)
  2. Coerce with Number() and validate Number.isInteger(v) && v > 0 before calling
  3. List available version files (v*.md in the versions dir) and pick a valid one
  4. Fix off-by-one logic where a 0-based index was passed instead of a 1-based version

Example fix

// before
await rollbackTo(skillPath, 0);
// after
const v = Number(targetVersion);
if (Number.isInteger(v) && v > 0) await rollbackTo(skillPath, v);
Defensive patterns

Strategy: validation

Validate before calling

const v = Number(targetVersion);
if (!Number.isInteger(v) || v <= 0) {
  throw new Error(`targetVersion must be a positive integer, got ${targetVersion}`);
}

Type guard

function isPositiveInteger(v) {
  return typeof v === 'number' && Number.isInteger(v) && v > 0;
}

Try / catch

try {
  await rollbackTo(skillPath, targetVersion);
} catch (err) {
  if (err.message.startsWith('Invalid target version')) {
    console.error(`Bad version '${targetVersion}' — use a 1-based integer`);
  } else throw err;
}

Prevention

When it happens

Trigger: Calling rollbackTo(skillPath, 'latest') or rollbackTo(skillPath, 0) or rollbackTo(skillPath, -1) or passing a float like 2.5; also passing a version object instead of a number.

Common situations: UI code forwarding user text straight into targetVersion; computing a version from an off-by-one index (0-based vs 1-based); accidentally passing an options object as the second argument after a signature change.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


AI-assisted analysis of affaan-m/ECC@8321021c54 (2026-09-16). Data as JSON: /api/errors/d40bf7eabaacd74f. Report an issue: GitHub.

Appendix: source

Thrown at scripts/lib/skill-evolution/versioning.js:188

    event: 'snapshot',
    version: nextVersion,
    reason: options.reason || null,
    author: options.author || null,
    status: 'applied',
    created_at: createdAt,
  });

  return {
    version: nextVersion,
    path: snapshotPath,
    created_at: createdAt,
  };
}

function rollbackTo(skillPath, targetVersion, options = {}) {
  const normalizedTargetVersion = Number(targetVersion);
  if (!Number.isInteger(normalizedTargetVersion) || normalizedTargetVersion <= 0) {
    throw new Error(`Invalid target version: ${targetVersion}`);
  }

  ensureSkillExists(skillPath);
  ensureSkillVersioning(skillPath);

  const targetPath = path.join(getVersionsDir(skillPath), `v${normalizedTargetVersion}.md`);
  if (!fs.existsSync(targetPath)) {
    throw new Error(`Version not found: v${normalizedTargetVersion}`);
  }

  const currentVersion = getCurrentVersion(skillPath);
  const targetContent = fs.readFileSync(targetPath, 'utf8');
  fs.writeFileSync(getSkillFilePath(skillPath), targetContent, 'utf8');

  const createdVersion = createVersion(skillPath, {
    timestamp: options.timestamp,
    reason: options.reason || `rollback to v${normalizedTargetVersion}`,
    author: options.author || null,

View on GitHub (pinned to 8321021c54)