ruvnet/ruflo · error · Error

Validation failed: ${result.error}

Error message

Validation failed: ${result.error}

What it means

Thrown by assertValid when a ValidationResult has valid=false. assertValid is the fail-fast bridge over the input-sanitization layer: it propagates the specific sub-error string (e.g. a null byte in a field, a disallowed value) via the interpolated message. It exists to turn soft validation failures into hard exceptions at trust boundaries.

Source

Thrown at v3/@claude-flow/cli-core/src/mcp-tools/validate-input.ts:201

      return { valid: false, sanitized: {}, error: `${label}["${name}"] must be a string` };
    }
    if (rawVal.length > 32_768) {
      return { valid: false, sanitized: {}, error: `${label}["${name}"] exceeds 32768 characters` };
    }
    if (rawVal.includes('\0')) {
      return { valid: false, sanitized: {}, error: `${label}["${name}"] contains a null byte` };
    }
    out[name] = rawVal;
  }
  return { valid: true, sanitized: out };
}

/**
 * Assert validation or throw with a structured error.
 */
export function assertValid(result: ValidationResult): string {
  if (!result.valid) {
    throw new Error(`Validation failed: ${result.error}`);
  }
  return result.sanitized;
}

// Try to load the full @claude-flow/security module for enhanced validation
// eslint-disable-next-line @typescript-eslint/no-explicit-any
let _securityModule: Record<string, any> | null = null;
let _securityLoaded = false;

async function getSecurityModule(): Promise<Record<string, any> | null> {
  if (_securityLoaded) return _securityModule;
  _securityLoaded = true;
  try {
    // Dynamic import — @claude-flow/security is an optional dependency
    _securityModule = await (Function('return import("@claude-flow/security")')() as Promise<Record<string, any>>);
  } catch {
    // @claude-flow/security is optional — fallback to inline validation above
  }

View on GitHub (pinned to 6b01dc5a68)

Solutions

  1. Inspect the full interpolated message — the suffix after 'Validation failed:' is the precise field and reason (e.g. label["name"] contains a null byte).
  2. Fix the input at the source: strip/normalize control characters or supply the missing required field before re-validating.
  3. If running a server, return a 400 with result.error to the client rather than letting assertValid throw an unhandled exception.
  4. Run validateInput separately and branch on result.valid so you can collect all field errors instead of failing on the first one.

Example fix

// before
const sanitized = assertValid(validateInput(params));

// after
const result = validateInput(params);
if (!result.valid) {
  return { status: 400, error: result.error };
}
const sanitized = result.sanitized;
Defensive patterns

Strategy: validation

Validate before calling

const result = validateInput(params);
if (!result.valid) {
  return { status: 400, error: result.error };
}
// only now is it safe to assertValid / use sanitized
const sanitized = result.sanitized;

Type guard

function isValidationOk(r: ValidationResult): r is { valid: true; sanitized: Record<string, unknown> } {
  return r.valid === true;
}

Try / catch

try {
  assertValid(result);
} catch (e) {
  // e.message === `Validation failed: ${result.error}`
  return { status: 400, error: (e as Error).message };
}

Prevention

When it happens

Trigger: Calling assertValid(result) where result came from a validate* function that detected unsafe input — a property containing a null byte, a value failing schema/type rules, or an unknown/extra field under strict mode. The message carries result.error verbatim, so the root cause is in the original validation result.

Common situations: Processing untrusted MCP/tool input that contains control characters (null bytes, odd unicode), client payloads with missing required fields, or version skew where a newer client sends fields the validator rejects. Common at the entry point of MCP tools that call assertValid immediately after validateInput.

Related errors


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