Skip to content

Conversation

@Lil-Duckling-22
Copy link

@Lil-Duckling-22 Lil-Duckling-22 commented Nov 15, 2025

Replace TODO comment with detailed error formatting for validation failures. Error messages now include property names and constraint details instead of generic toString() output, making it easier to identify validation issues.

Summary by CodeRabbit

  • Bug Fixes

    • Validation errors now show structured, multi-line messages with per-property details and precise paths (including nested fields and array indices) for clearer diagnostics.
  • Tests

    • Added comprehensive unit tests covering invalid and valid manifests, nested-field validations, array-indexed paths, and the enhanced error-message formatting.

✏️ Tip: You can customize this high-level summary in your review settings.

Replace TODO comment with detailed error formatting for validation failures.
Error messages now include property names and constraint details instead
of generic toString() output, making it easier to identify validation issues.
@coderabbitai
Copy link

coderabbitai bot commented Nov 15, 2025

Walkthrough

Validation error formatting was changed to recursively format class-validator ValidationError objects (including nested children and array indices) using a new formatValidationErrors helper instead of toString(). A new test suite was added to verify structured, per-property error messages and a positive validation path.

Changes

Cohort / File(s) Summary
Loader: error formatting update
packages/common/src/project/load.ts
Import formatValidationErrors and use it to format validation failures before throwing, replacing prior toString()-based messages.
Shared formatter / utils
packages/common/src/project/utils.ts
Added formatValidationErrors to recursively format ValidationError trees (handles nested children and array indices) and switched validation flows to use it.
Versioned manifest base
packages/common/src/project/versioned/base.ts
Import and use formatValidationErrors in validate() to produce structured, newline-delimited error messages instead of error.toString().
Tests
packages/common/src/project/load.spec.ts
New tests covering missing/invalid fields, nested object/array error paths, empty-string/version constraints, and a successful manifest validation case.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20–30 minutes

  • Check recursive handling of ValidationError.children and correct path composition for nested properties and array indices.
  • Verify error message formatting matches tests (prefix, per-property lines, and multi-line output).
  • Confirm thrown error types and external behavior remain unchanged.
  • Review new tests for completeness and potential edge cases.

Poem

I hop through manifests, nibbling each line,
I tidy the errors to make them align.
"project validation failed" — each field gets its say,
Nested paths and arrays, all listed today. 🐰✨

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 40.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main change: improving validation error details in validateCommonProjectManifest by adding structured error formatting.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

📜 Recent review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 7aa34f3 and c5c19c7.

📒 Files selected for processing (4)
  • packages/common/src/project/load.spec.ts (1 hunks)
  • packages/common/src/project/load.ts (2 hunks)
  • packages/common/src/project/utils.ts (2 hunks)
  • packages/common/src/project/versioned/base.ts (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (3)
  • packages/common/src/project/utils.ts
  • packages/common/src/project/load.ts
  • packages/common/src/project/load.spec.ts
🧰 Additional context used
📓 Path-based instructions (2)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.{ts,tsx}: Use TypeScript throughout with strict configuration in the monorepo
Use Ethers.js for Ethereum integration

Files:

  • packages/common/src/project/versioned/base.ts
packages/**/src/**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

Run ESLint with TypeScript support, Prettier, and various plugins across all TypeScript files using configured husky pre-commit hooks and lint-staged

Files:

  • packages/common/src/project/versioned/base.ts
🧬 Code graph analysis (1)
packages/common/src/project/versioned/base.ts (1)
packages/common/src/project/utils.ts (1)
  • formatValidationErrors (208-232)
🔇 Additional comments (2)
packages/common/src/project/versioned/base.ts (2)

24-24: LGTM! Centralized error formatting addresses duplication concern.

The import of formatValidationErrors from ../utils provides a single, centralized implementation, addressing the previous review feedback about function duplication across multiple files.


56-57: LGTM! Improved error formatting provides better validation feedback.

The usage of formatValidationErrors(errors).join('\n') replaces the generic toString() approach with structured, detailed error messages that include property paths and constraint details. This makes validation failures much easier to diagnose, addressing the PR objectives effectively.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (1)
packages/common/src/project/load.ts (1)

94-98: Excellent improvement to error messaging.

The structured error formatting is much more actionable than generic toString() output. The defensive check for constraints and clear property-level formatting will help developers quickly identify validation issues.

One optional enhancement: ValidationError objects can have nested errors via the children property for complex object validations. If manifest structures become more deeply nested in the future, consider recursively handling these children.

Example recursive approach if nested validation becomes relevant:

const formatError = (error: ValidationError, indent = '  '): string => {
  const property = error.property;
  const constraints = error.constraints ? Object.values(error.constraints).join(', ') : '';
  let message = `${indent}- ${property}${constraints ? ': ' + constraints : ''}`;
  
  if (error.children?.length) {
    const childMessages = error.children.map(child => formatError(child, indent + '  ')).join('\n');
    message += '\n' + childMessages;
  }
  
  return message;
};

const errorMsgs = errors.map(error => formatError(error)).join('\n');
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 45e1b6b and b26630d.

📒 Files selected for processing (1)
  • packages/common/src/project/load.ts (2 hunks)
🔇 Additional comments (1)
packages/common/src/project/load.ts (1)

8-8: Good addition for type safety.

Adding the ValidationError type import enables proper type annotation in the error formatting logic, improving code maintainability and IDE support.

@stwiname
Copy link
Collaborator

Hi @Lil-Duckling-22, thanks for your PR. Can you please update tests and provide an example of how the error output has changed

@Lil-Duckling-22
Copy link
Author

@stwiname sure thing, here are the tests

@stwiname
Copy link
Collaborator

stwiname commented Dec 7, 2025

How do the errors look for an error in a child object? e.g. An invalid filter on a mapping handler

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (1)
packages/common/src/project/versioned/base.ts (1)

54-83: Private ValidationError formatter is correct but duplicates utils.ts logic

The private formatValidationErrors mirrors the utils.ts helper: it builds dotted paths, uses [index] for numeric property values, and walks children recursively. This is correct for class-validator’s nested error trees and will produce paths like dataSources[0].mapping.handlers[1].filter.

However, this is now duplicated with formatValidationErrors in packages/common/src/project/utils.ts. Consider centralizing this formatter (e.g., exporting it from utils.ts or a dedicated validation utility module) and reusing it here to keep error formatting consistent and reduce maintenance overhead if the format ever changes.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between ff31007 and 7aa34f3.

📒 Files selected for processing (4)
  • packages/common/src/project/load.spec.ts (1 hunks)
  • packages/common/src/project/load.ts (2 hunks)
  • packages/common/src/project/utils.ts (2 hunks)
  • packages/common/src/project/versioned/base.ts (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • packages/common/src/project/load.ts
  • packages/common/src/project/load.spec.ts
🧰 Additional context used
📓 Path-based instructions (2)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.{ts,tsx}: Use TypeScript throughout with strict configuration in the monorepo
Use Ethers.js for Ethereum integration

Files:

  • packages/common/src/project/utils.ts
  • packages/common/src/project/versioned/base.ts
packages/**/src/**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

Run ESLint with TypeScript support, Prettier, and various plugins across all TypeScript files using configured husky pre-commit hooks and lint-staged

Files:

  • packages/common/src/project/utils.ts
  • packages/common/src/project/versioned/base.ts
🧬 Code graph analysis (1)
packages/common/src/project/utils.ts (1)
packages/common/src/project/versioned/base.ts (1)
  • formatValidationErrors (59-83)
🔇 Additional comments (3)
packages/common/src/project/utils.ts (2)

203-232: Structured ValidationError formatter correctly handles nesting and array indices

The recursive formatter looks solid: it builds property paths with parent.child and [index] for numeric property values, and only emits lines when constraints exist while still recursing into children. This should yield clear messages like dataSources[0].mapping.handlers[1].filter: ... for deeply nested validation issues.


234-239: validateObject now surfaces per-property, multi-line validation details

Switching from a generic toString() to formatValidationErrors(errors).join('\n') significantly improves debuggability while preserving the existing errorMessage prefix. Callers will now see one line per failing property, including full paths into child objects/arrays, which aligns with the new manifest validation behavior.

packages/common/src/project/versioned/base.ts (1)

85-90: validate() now throws a clear, multi-line manifest parse error with full property paths

Using validateSync(this.deployment, {whitelist: true, forbidNonWhitelisted: true}) combined with this.formatValidationErrors(errors).join('\n') produces a concise header (Failed to parse project...) followed by one bullet per invalid property, including nested/array paths. For example, an invalid filter on a handler inside a mapping should show up as something like:

- dataSources[0].mapping.handlers[1].filter: <constraint messages>

This is a meaningful improvement over the previous error.toString() output and directly addresses the need to understand errors in child objects.

Comment on lines 54 to 83
/**
* Recursively formats validation errors into a structured format.
* Handles nested errors (errors with children) by recursively processing them.
* Formats array indices with brackets for better readability (e.g., dataSources[0].mapping.handlers[1].filter).
*/
private formatValidationErrors(errors: ValidationError[], parentPath = ''): string[] {
const errorMessages: string[] = [];

for (const error of errors) {
// Check if property is a numeric string (array index)
const isArrayIndex = /^\d+$/.test(error.property);
const propertyPath = parentPath
? isArrayIndex
? `${parentPath}[${error.property}]`
: `${parentPath}.${error.property}`
: error.property;

if (error.constraints && Object.keys(error.constraints).length > 0) {
const constraints = Object.values(error.constraints).join(', ');
errorMessages.push(` - ${propertyPath}: ${constraints}`);
}

// Recursively handle nested errors
if (error.children && error.children.length > 0) {
errorMessages.push(...this.formatValidationErrors(error.children, propertyPath));
}
}

return errorMessages;
}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This function is also defined in utils.ts and load.ts. Please just provide one implementation

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All tests that have a try/catch should also have a fail call. If the function being tested doesn't throw then there will be no expectations.

Comment on lines 269 to 276
// For nested array errors, the path should use bracket notation
// Example: dataSources[0].mapping.handlers[1].filter.specVersion
// Note: The exact path depends on class-validator's error structure,
// but we verify that array indices are formatted with brackets
const hasArrayIndexFormat = /\[\d+\]/.test(errorMessage);

// The error message should be structured and readable
expect(errorMessage).toMatch(/ - .+:/);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think this is sufficient validation of the error message. We should be able to expect a full message example

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants