{"record":{"id":"068badbee170b383","repo":"ruvnet/ruflo","slug":"validation-failed-result-error","errorCode":null,"errorMessage":"Validation failed: ${result.error}","messagePattern":"Validation failed: (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"v3/@claude-flow/cli-core/src/mcp-tools/validate-input.ts","lineNumber":201,"sourceCode":"      return { valid: false, sanitized: {}, error: `${label}[\"${name}\"] must be a string` };\n    }\n    if (rawVal.length > 32_768) {\n      return { valid: false, sanitized: {}, error: `${label}[\"${name}\"] exceeds 32768 characters` };\n    }\n    if (rawVal.includes('\\0')) {\n      return { valid: false, sanitized: {}, error: `${label}[\"${name}\"] contains a null byte` };\n    }\n    out[name] = rawVal;\n  }\n  return { valid: true, sanitized: out };\n}\n\n/**\n * Assert validation or throw with a structured error.\n */\nexport function assertValid(result: ValidationResult): string {\n  if (!result.valid) {\n    throw new Error(`Validation failed: ${result.error}`);\n  }\n  return result.sanitized;\n}\n\n// Try to load the full @claude-flow/security module for enhanced validation\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nlet _securityModule: Record<string, any> | null = null;\nlet _securityLoaded = false;\n\nasync function getSecurityModule(): Promise<Record<string, any> | null> {\n  if (_securityLoaded) return _securityModule;\n  _securityLoaded = true;\n  try {\n    // Dynamic import — @claude-flow/security is an optional dependency\n    _securityModule = await (Function('return import(\"@claude-flow/security\")')() as Promise<Record<string, any>>);\n  } catch {\n    // @claude-flow/security is optional — fallback to inline validation above\n  }","sourceCodeStart":183,"sourceCodeEnd":219,"githubUrl":"https://github.com/ruvnet/ruflo/blob/fa13ee4ad60ac2090b1480656eb233521790d640/v3/@claude-flow/cli-core/src/mcp-tools/validate-input.ts#L183-L219","documentation":"assertValid is the throwing wrapper over the ValidationResult returned by the validate-input validators (validatePath, validateText, validateIdentifier, validateEnv, …). When result.valid is false it throws with the specific rule that fired embedded in the message — null bytes, path traversal, shell metacharacters, length caps, denylisted env names, bad types. Hitting it means the input failed schema/security validation and the code path chose exceptions over branching.","triggerScenarios":"assertValid(validatePath(v, 'file_path')) where v is empty, over 4096 chars, contains '..' or shell metacharacters like ; & | $() backticks; assertValid(validateText(...)) on a non-string or >10,000-char value; assertValid(validateEnv(env)) where a key is LD_PRELOAD/NODE_OPTIONS, is not a POSIX name, or a value contains a null byte.","commonSituations":"MCP tool handlers validating untrusted tool_input; user-supplied env objects containing NODE_OPTIONS; long descriptions exceeding the 10k cap; paths that legitimately contain '$' or parentheses being sent to shell execution.","solutions":["Read result.error for the exact rule that fired and fix the input (remove metacharacters/null bytes, shorten the string, drop denylisted env keys)","For user-facing inputs prefer the non-throwing API: branch on result.valid and return a typed error instead of assertValid","For Windows paths rely on validatePath's backslash normalization; avoid shell metacharacters in any path handed to a shell","Add unit tests for each rejection rule so regressions in the sanitizer surface locally"],"exampleFix":"// before\nconst path = assertValid(validatePath(input.file_path, 'file_path'));\n\n// after\nconst res = validatePath(input.file_path, 'file_path');\nif (!res.valid) {\n  return { error: `invalid file_path: ${res.error}` }; // typed error to caller\n}\nconst path = res.sanitized;","handlingStrategy":"validation","validationCode":"const res = validatePath(input.file_path, 'file_path');\nif (!res.valid) {\n  return { error: `invalid file_path: ${res.error}` };\n}\nconst filePath = res.sanitized;","typeGuard":"function isValidationResultOk(r: ValidationResult): r is { valid: true; sanitized: string } {\n  return r.valid;\n}","tryCatchPattern":"try { value = assertValid(validateText(raw, 'description')); }\ncatch (e) { if (e instanceof Error && e.message.startsWith('Validation failed')) { replyToCaller(e.message); } else throw e; }","preventionTips":["Branch on result.valid for user-supplied input; reserve assertValid for trusted internal invariants","Test each validator rule (null byte, traversal, metacharacter, length, denylist) in CI","Surface result.error verbatim to callers so they can fix the offending field"],"tags":["validation","input-sanitization","security","mcp","typescript"],"backgroundTag":"input-validation-failed","analyzedSha":"fa13ee4ad60ac2090b1480656eb233521790d640","analyzedAt":"2026-08-18T21:34:22.708Z","contentChangedAt":"2026-08-18T21:34:22.708Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}