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
- Check the label in the message to identify which declaration field is blank
- Populate the field or remove the empty declaration entirely — empty arrays are accepted, blank entries are not
- 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
- Make declaration fields required (non-optional strings) in your own types so blanks fail type-check
- Trim at the boundary where declarations are authored or deserialized
- Reject blank rows during config load with row context instead of at evidence hashing
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
- ${label} must be a canonical sha256 digest
- build evidence path is not a file or symlink: ${path}
- duplicate declared build input
- duplicate declared toolchain
- unsafe build input path: ${value}
AI-assisted analysis of ruvnet/ruflo@fa13ee4ad6 (2026-08-18).
Data as JSON: /api/errors/ce4a57e83dd36f9e.
Report an issue: GitHub.