Fission-AI/OpenSpec · error · Error

Invalid change name

Error message

Invalid change name '${changeName}': ${lookupError}

What it means

Path-traversal guard in validateChangeExists: validateChangeLookupName rejected the change name's format (e.g. it contains slashes or other unsafe characters), so it is never joined onto the changes directory. The embedded lookupError text names the specific rule violated.

Solutions

  1. Use a plain kebab-case change name without path separators or traversal segments
  2. Check the appended reason for the exact rule violated
Defensive patterns

Strategy: validation

When it happens

Trigger: Thrown at src/commands/workflow/shared.ts:207 when the library encounters an invalid state.

Common situations: See trigger scenarios.


AI-assisted analysis of Fission-AI/OpenSpec@6926ccb18a (2026-08-25). Data as JSON: /api/errors/e73c5cbf6bcf0538. Report an issue: GitHub.

Appendix: source

Thrown at src/commands/workflow/shared.ts:207

): Promise<string> {
  // Hints must stay pasteable: callers with a selected store pass a
  // store-carrying hint so following it lands in the same root.
  const newChangeHint = hints.newChangeHint ?? 'openspec new change <name>';

  if (!changeName) {
    const available = await getAvailableChanges(projectRoot, changesDir);
    if (available.length === 0) {
      throw new Error(`No changes found. Create one with: ${newChangeHint}`);
    }
    throw new Error(
      `Missing required option --change. Available changes:\n  ${available.join('\n  ')}`
    );
  }

  // Validate change name format to prevent path traversal
  const lookupError = validateChangeLookupName(changeName);
  if (lookupError) {
    throw new Error(`Invalid change name '${changeName}': ${lookupError}`);
  }

  // Check directory existence directly
  const changePath = path.join(changesDir, changeName);
  const exists = fs.existsSync(changePath) && fs.statSync(changePath).isDirectory();

  if (!exists) {
    const available = await getAvailableChanges(projectRoot, changesDir);
    if (available.length === 0) {
      throw new Error(
        `Change '${changeName}' not found. No changes exist. Create one with: ${newChangeHint}`
      );
    }
    throw new Error(
      `Change '${changeName}' not found. Available changes:\n  ${available.join('\n  ')}`
    );
  }

View on GitHub (pinned to 6926ccb18a)