Fission-AI/OpenSpec · error · Error

No changes found. Create one with

Error message

No changes found. Create one with: ${newChangeHint}

What it means

Generic guard thrown by validateChangeExists when no openspec/changes directory entries are found, so there is no change to operate on. The named input at fault is the change name (or its absence); the error is a sentinel telling the user to create a change first, including a pasteable hint command.

Solutions

  1. Run the newChangeHint command shown in the error (e.g. 'openspec new change') to create a change
  2. Verify you are in the correct project root — the changes directory looked up is openspec/changes relative to it
  3. Check for typos in the change name if you passed one
Defensive patterns

Strategy: validation

When it happens

Trigger: Thrown at src/commands/workflow/shared.ts:197 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/22ca922c6e4cfc0d. Report an issue: GitHub.

Appendix: source

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

/**
 * Validates that a change exists and returns available changes if not.
 * Checks directory existence directly to support scaffolded changes (without proposal.md).
 */
export async function validateChangeExists(
  changeName: string | undefined,
  projectRoot: string,
  changesDir = path.join(projectRoot, 'openspec', 'changes'),
  hints: { newChangeHint?: string } = {}
): 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);

View on GitHub (pinned to 6926ccb18a)