{"record":{"id":"d40bf7eabaacd74f","repo":"affaan-m/ECC","slug":"invalid-target-version-targetversion","errorCode":null,"errorMessage":"Invalid target version: ${targetVersion}","messagePattern":"Invalid target version: (.+?)","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"scripts/lib/skill-evolution/versioning.js","lineNumber":188,"sourceCode":"    event: 'snapshot',\n    version: nextVersion,\n    reason: options.reason || null,\n    author: options.author || null,\n    status: 'applied',\n    created_at: createdAt,\n  });\n\n  return {\n    version: nextVersion,\n    path: snapshotPath,\n    created_at: createdAt,\n  };\n}\n\nfunction rollbackTo(skillPath, targetVersion, options = {}) {\n  const normalizedTargetVersion = Number(targetVersion);\n  if (!Number.isInteger(normalizedTargetVersion) || normalizedTargetVersion <= 0) {\n    throw new Error(`Invalid target version: ${targetVersion}`);\n  }\n\n  ensureSkillExists(skillPath);\n  ensureSkillVersioning(skillPath);\n\n  const targetPath = path.join(getVersionsDir(skillPath), `v${normalizedTargetVersion}.md`);\n  if (!fs.existsSync(targetPath)) {\n    throw new Error(`Version not found: v${normalizedTargetVersion}`);\n  }\n\n  const currentVersion = getCurrentVersion(skillPath);\n  const targetContent = fs.readFileSync(targetPath, 'utf8');\n  fs.writeFileSync(getSkillFilePath(skillPath), targetContent, 'utf8');\n\n  const createdVersion = createVersion(skillPath, {\n    timestamp: options.timestamp,\n    reason: options.reason || `rollback to v${normalizedTargetVersion}`,\n    author: options.author || null,","sourceCodeStart":170,"sourceCodeEnd":206,"githubUrl":"https://github.com/affaan-m/ECC/blob/8321021c54d670126ce3b2969d5deb880b4b0c2a/scripts/lib/skill-evolution/versioning.js#L170-L206","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Pass a positive integer, e.g. rollbackTo(skillPath, 2)","Coerce with Number() and validate Number.isInteger(v) && v > 0 before calling","List available version files (v*.md in the versions dir) and pick a valid one","Fix off-by-one logic where a 0-based index was passed instead of a 1-based version"],"exampleFix":"// before\nawait rollbackTo(skillPath, 0);\n// after\nconst v = Number(targetVersion);\nif (Number.isInteger(v) && v > 0) await rollbackTo(skillPath, v);","handlingStrategy":"validation","validationCode":"const v = Number(targetVersion);\nif (!Number.isInteger(v) || v <= 0) {\n  throw new Error(`targetVersion must be a positive integer, got ${targetVersion}`);\n}","typeGuard":"function isPositiveInteger(v) {\n  return typeof v === 'number' && Number.isInteger(v) && v > 0;\n}","tryCatchPattern":"try {\n  await rollbackTo(skillPath, targetVersion);\n} catch (err) {\n  if (err.message.startsWith('Invalid target version')) {\n    console.error(`Bad version '${targetVersion}' — use a 1-based integer`);\n  } else throw err;\n}","preventionTips":["Parse user input with Number.parseInt before calling, never pass raw strings","Remember versions are 1-based; convert 0-based indexes with idx + 1","Keep argument order (skillPath, targetVersion, options) — don't shift args","Add CLI validation that rejects non-numeric version input"],"tags":["validation","versions"],"backgroundTag":"invalid-argument-value","analyzedSha":"8321021c54d670126ce3b2969d5deb880b4b0c2a","analyzedAt":"2026-09-16T10:08:13.343Z","contentChangedAt":"2026-09-16T10:08:13.343Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}