affaan-m/ECC · error · Error

Version not found: v

Error message

Version not found: v${normalizedTargetVersion}

What it means

rollbackTo throws this after validating the version number when the corresponding snapshot file v<n>.md does not exist in the skill's versions directory. The version integer is valid but there is no stored snapshot to roll back to. This protects against restoring an empty or wrong file.

Solutions

  1. List files in the skill's versions directory and pick an existing v<n>.md version number
  2. Restore the missing versions directory from git or backups
  3. Confirm the skillPath points at the skill whose history contains that version
  4. Capture the missing version via the library's save/commit-version flow before rolling back

Example fix

// before
await rollbackTo(skillPath, 9); // v9.md never saved
// after
const available = fs.readdirSync(getVersionsDir(skillPath)).map(f => parseInt(f.slice(1)));
await rollbackTo(skillPath, Math.max(...available));
Defensive patterns

Strategy: fallback

Validate before calling

const fs = require('fs');
const target = require('path').join(versionsDir, `v${v}.md`);
if (!fs.existsSync(target)) {
  const available = fs.readdirSync(versionsDir)
    .filter(f => /^v\d+\.md$/.test(f))
    .map(f => parseInt(f.slice(1)));
  console.error(`v${v} missing; available: ${available.sort((a,b)=>a-b).join(', ')}`);
}

Type guard

function versionExists(skillPath, v) {
  return fs.existsSync(path.join(getVersionsDir(skillPath), `v${v}.md`));
}

Try / catch

try {
  await rollbackTo(skillPath, v);
} catch (err) {
  if (err.message.startsWith('Version not found')) {
    const match = err.message.match(/v(\d+)/);
    console.error(`Snapshot v${match[1]} absent — restore versions dir or pick another`);
  } else throw err;
}

Prevention

When it happens

Trigger: Calling rollbackTo with an integer > 0 that was never captured, e.g. version 5 when only v1–v3 exist; versions directory deleted or pruned; wrong skillPath so the lookup hits a directory without that history.

Common situations: Guessing the latest version number instead of listing files; CI cleaning up versions/ directories as build artifacts; switching machines without copying version history; rolling back a different skill than the one whose history you consulted.

Understand the failure class

Background: 'Could not be found', 'does not exist', 'not found in database': the resource-not-found family when an ID, slug, key, or URI lookup comes back empty — this error's family across 20 libraries.

Related errors


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

Appendix: source

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

  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,
  });

  appendEvolutionRecord(skillPath, 'amendments', {
    event: 'rollback',
    version: createdVersion.version,
    source_version: currentVersion,
    target_version: normalizedTargetVersion,
    reason: options.reason || null,

View on GitHub (pinned to 8321021c54)