ruvnet/ruflo · error · Error

label may only contain [A-Za-z0-9_.\-:/@]

Error message

label may only contain [A-Za-z0-9_.\-:/@]

What it means

Thrown by validateLabel() when the label is present but fails the allow-list `/^[A-Za-z0-9_.\-:/@]+$/` (length>256 is a separate throw). Note this set is slightly narrower than agentbbs's — it does NOT include `#` — because agenticow labels become filesystem path segments in the lineage manifest and a `#` would be legal-but-confusing on case-sensitive filesystems. Spaces, commas, and shell metacharacters are rejected because labels are embedded in manifest JSON keys and branch paths.

Source

Thrown at v3/@claude-flow/cli/src/mcp-tools/agenticow-loader.ts:91

  return isAbsolute(path) ? path : resolve(getProjectCwd(), path);
}

/**
 * Lineage manifest companion path. agenticow persists the COW chain
 * (working → checkpoints → base) into `<file>.agenticow.json` next to the
 * `.rvf` data file. Without it, forks/checkpoints are in-memory only and
 * disappear when the AgenticMemory handle closes.
 */
export function manifestFor(file: string): string {
  return `${file}.agenticow.json`;
}

/** Validate a COW branch/checkpoint label (alnum + a small safe symbol set). */
export function validateLabel(label: string): string {
  if (!label || typeof label !== 'string') throw new Error('label is required');
  if (label.length > 256) throw new Error('label exceeds 256 chars');
  if (!/^[A-Za-z0-9_.\-:/@]+$/.test(label)) {
    throw new Error('label may only contain [A-Za-z0-9_.\\-:/@]');
  }
  return label;
}

/**
 * Open (or create) a memory file, restoring its COW chain from the lineage
 * manifest when one exists. When neither the `.rvf` nor the manifest exists,
 * `dimension` is required to create a fresh base.
 */
export async function openWithLineage(api: AgenticowApi, file: string, dimension?: number) {
  const manifest = manifestFor(file);
  if (existsSync(manifest)) {
    return (api.AgenticMemory as any).load(manifest);
  }
  const opts: any = {};
  if (typeof dimension === 'number' && Number.isInteger(dimension) && dimension > 0) {
    opts.dimension = dimension;
  } else if (!existsSync(file)) {

View on GitHub (pinned to 6b01dc5a68)

Solutions

  1. Restrict agenticow labels to alphanumerics and `_ . - : / @` (no `#`).
  2. If migrating labels from agentbbs, strip leading `#` first.
  3. Sanitize/slugify upstream and keep labels ≤256 chars.

Example fix

// before — agentbbs-style label reused
speculate({ basePath, candidates: [{ label: '#exp-a', ingest }] });
// after
speculate({ basePath, candidates: [{ label: 'exp-a', ingest }] });
Defensive patterns

Strategy: validation

Validate before calling

const LABEL_RE = /^[A-Za-z0-9_.\-:/@]+$/;
function normalizeAgenticowLabel(label: string): string {
  const v = label.replace(/^#/, '').trim();
  if (!LABEL_RE.test(v)) throw new Error('label has disallowed chars (no # allowed)');
  return v;
}

Type guard

const isAgenticowLabel = (v: string): boolean =>
  v.length > 0 && v.length <= 256 && /^[A-Za-z0-9_.\-:/@]+$/.test(v);

Try / catch

null

Prevention

When it happens

Trigger: Label contains a space, `#`, comma, or other punctuation; an agentbbs-style '#sales' label reused as an agenticow branch label; unicode; a templated label joined with a disallowed separator.

Common situations: Cross-tool reuse of a label string that is valid in agentbbs but not here; free-form user input; a separator like '/' that is allowed but combined with a leading '#'.

Related errors


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