ruvnet/ruflo · error · Error

Manifest not found: ${localPath}

Error message

Manifest not found: ${localPath}

What it means

Thrown by loadLocalWitness() when existsSync(localPath) returns false. The local manifest path supplied to the verify command's --local option does not exist on disk, so the witness cannot be read.

Source

Thrown at v3/@claude-flow/cli/src/commands/verify.ts:70

  };
}

const DEFAULT_MANIFEST_URL = 'https://raw.githubusercontent.com/ruvnet/ruflo/{branch}/verification.md.json';

async function fetchWitness(branch: string): Promise<Witness> {
  const url = DEFAULT_MANIFEST_URL.replace('{branch}', branch);
  // audit_1776853149979: bare fetch had no timeout — a hung GitHub CDN would
  // pin the verify command indefinitely. 30s is generous for a sub-MB JSON.
  const res = await fetch(url, { signal: AbortSignal.timeout(30000) });
  if (!res.ok) {
    throw new Error(`Failed to fetch manifest from ${url}: ${res.status} ${res.statusText}`);
  }
  return await res.json() as Witness;
}

function loadLocalWitness(localPath: string): Witness {
  if (!existsSync(localPath)) {
    throw new Error(`Manifest not found: ${localPath}`);
  }
  return JSON.parse(readFileSync(localPath, 'utf-8')) as Witness;
}

/**
 * Locate the user's installed package root.
 *
 * The witness manifest paths are repo-relative (e.g.
 * "v3/@claude-flow/cli/dist/src/mcp-tools/hooks-tools.js"). For
 * end users, only the dist/ subtree ships in node_modules. We map
 * the repo path → the installed equivalent by stripping the
 * "v3/@claude-flow/<pkg>/" prefix and looking up node_modules/<pkg>/.
 */
function repoPathToInstalledPath(repoPath: string): string | null {
  // Match v3/@claude-flow/<pkg>/<rest>
  const match = repoPath.match(/^v3\/(@claude-flow\/[^/]+)\/(.+)$/);
  if (match) {
    const pkg = match[1];

View on GitHub (pinned to 6b01dc5a68)

Solutions

  1. Use an absolute path to the manifest file.
  2. Expand `~` explicitly: `path.resolve(process.env.HOME, '...', 'verification.md.json')`.
  3. Confirm the file exists: `ls -l <path>`; re-download it if missing.
  4. If you intended the remote fetch, omit --local entirely.

Example fix

// before
ruflo verify --local ~/manifests/verify.json   // '~' not expanded
// after
ruflo verify --local "$HOME/manifests/verify.json"
Defensive patterns

Strategy: validation

Validate before calling

function resolveLocalManifest(p: string): string {
  const expanded = p.startsWith('~/')
    ? require('path').join(process.env.HOME ?? '', p.slice(2))
    : require('path').resolve(p);
  if (!require('fs').existsSync(expanded)) {
    throw new Error(`Manifest not found: ${expanded}`);
  }
  return expanded;
}

Type guard

const isExistingFile = (p: string): boolean =>
  require('fs').existsSync(require('path').resolve(p.replace(/^~/, process.env.HOME ?? '')));

Try / catch

try {
  loadLocalWitness(localPath);
} catch (e) {
  const msg = e instanceof Error ? e.message : String(e);
  if (msg.startsWith('Manifest not found')) {
    console.error('File does not exist. Use an absolute path; ~ is not expanded.');
    process.exit(2);
  }
  throw e;
}

Prevention

When it happens

Trigger: Passing a --local path that is misspelled, relative to the wrong working directory, or pointing at a file that was not yet downloaded/copied.

Common situations: Relative path resolved against an unexpected cwd, the manifest download step was skipped, the path uses `~` which Node does not expand, or a typo in the filename.

Related errors


AI-assisted analysis of ruvnet/ruflo@6b01dc5a68 (2026-08-12). Data as JSON: /api/errors/35556c7626a1d379. Report an issue: GitHub.