ruvnet/ruflo · error

${label} must be non-empty

Error message

${label} must be non-empty

What it means

createBuildEvidence trims every declared string — build input name, build input path (via normalizePath), toolchain name, and toolchain version — and throws when the trimmed result is empty. The label in the message identifies the exact field that failed (e.g. 'build input name must be non-empty').

Source

Thrown at v3/@claude-flow/codex/src/harness/build-evidence.ts:55

  path: string;
}

export interface BuildEvidence {
  contractVersion: 1;
  assurance: 'declared-unsigned';
  sourceStateId: string;
  buildInputs: readonly DeclaredBuildInput[];
  toolchains: readonly DeclaredToolchain[];
  evidenceDigest: string;
}

function compare(left: string, right: string): number {
  return left < right ? -1 : left > right ? 1 : 0;
}

function requireText(value: string, label: string): string {
  const result = value.trim();
  if (!result) throw new Error(`${label} must be non-empty`);
  return result;
}

function requireDigest(value: string, label: string): string {
  if (!DIGEST.test(value)) throw new Error(`${label} must be a canonical sha256 digest`);
  return value;
}

function normalizePath(value: string): string {
  const path = requireText(value, 'build input path');
  if (
    path.includes('\\')
    || path.startsWith('/')
    || path.startsWith('-')
    || path !== path.normalize('NFC')
    || path.split('/').some((part) => !part || part === '.' || part === '..')
  ) {
    throw new Error(`unsafe build input path: ${value}`);

View on GitHub (pinned to fa13ee4ad6)

Solutions

  1. Check the label in the message to identify which declaration field is blank
  2. Populate the field or remove the empty declaration entirely — empty arrays are accepted, blank entries are not
  3. When generating declarations programmatically, trim and assert non-empty at the source that builds them

Example fix

// before
const buildInputs = [
  { name: '   ', path: 'dist/app.js', digest: d, bytes: 1024 }, // blank name
];

// after
const buildInputs = [
  { name: 'app-bundle', path: 'dist/app.js', digest: d, bytes: 1024 },
];
Defensive patterns

Strategy: validation

Validate before calling

function validateDeclarations(inputs: { name: string }[], tools: { name: string; version: string }[]): void {
  for (const i of inputs) if (!i.name.trim()) throw new Error('build input name is blank');
  for (const t of tools) {
    if (!t.name.trim()) throw new Error('toolchain name is blank');
    if (!t.version.trim()) throw new Error('toolchain version is blank');
  }
}

Try / catch

Catch around createBuildEvidence/captureBuildEvidence and map the '<label> must be non-empty' message back to the offending declaration index so users see which entry (not just which field) is blank.

Prevention

When it happens

Trigger: A DeclaredBuildInput or ToolchainDeclaration whose name or version is '', ' ', or whitespace-only; a build input path that is blank (fails before the unsafe-path checks run).

Common situations: Optional string fields left as '' instead of omitted; declaration objects built from missing keys; placeholders like 'TODO' removed by a trim before the call; config generators emitting blank rows for skipped entries.

Related errors


AI-assisted analysis of ruvnet/ruflo@fa13ee4ad6 (2026-08-18). Data as JSON: /api/errors/ce4a57e83dd36f9e. Report an issue: GitHub.