Skip to content

feat: provide better panic msgs and docs#153

Merged
Oudwins merged 2 commits intomasterfrom
feat/better-panic-msgs
May 3, 2025
Merged

feat: provide better panic msgs and docs#153
Oudwins merged 2 commits intomasterfrom
feat/better-panic-msgs

Conversation

@Oudwins
Copy link
Owner

@Oudwins Oudwins commented May 3, 2025

Summary by CodeRabbit

  • New Features
    • Added detailed documentation on panic scenarios, including a new dedicated page explaining panic causes and solutions.
  • Bug Fixes
    • Improved error handling by introducing explicit type assertion checks to prevent unexpected panics and provide clearer diagnostic messages.
  • Documentation
    • Updated core design documentation with clickable links to panic-related resources.
    • Added comprehensive examples and explanations for panic cases.
  • Tests
    • Introduced a new test to verify panic behavior when schema definitions do not match struct fields.
  • Refactor
    • Standardized panic handling with centralized functions and improved context reporting for easier debugging.
    • Enhanced safe string conversion to handle nested pointers and nil values robustly.
    • Added string representation method for schema context to aid debugging.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented May 3, 2025

Caution

Review failed

The pull request is closed.

Walkthrough

This set of changes introduces robust type assertion checks and centralized panic handling across schema validation and parsing logic. Type assertions on context value pointers are now performed using safe, checked idioms; if a type mismatch is detected, a standardized panic function is invoked with detailed diagnostic information. New constants and a utility for formatted panics are added, and a String() method is implemented for the schema context to aid error reporting. Documentation is expanded with a dedicated page on panic scenarios, and a new test ensures panics are raised for schema-struct mismatches. Minor documentation improvements are also included.

Changes

File(s) Change Summary
custom.go, preprocess.go, zogSchema.go Added explicit, checked type assertions for context value pointers in processing and validation methods; replaced unchecked assertions with calls to a centralized panic function (Panicf) providing detailed error messages on failure.
internals/panics.go New file defining panic message constants and a utility function (Panicf) for formatted panics in schema/type error scenarios.
internals/contexts.go Added a String() method to SchemaCtx for formatted, detailed context reporting.
internals/utils.go Improved SafeString to safely handle nested and nil pointers using reflection.
struct.go Replaced direct panic calls with standardized Panicf invocation for missing struct fields during schema processing.
docs/docs/core-design-decisions.md Updated a caution heading to a markdown link pointing to the new panics documentation.
docs/docs/panics.md New documentation page describing when and why panics occur, with categorized examples and guidance.
struct_validate_test.go Added a test verifying that schema-struct mismatches correctly trigger panics during validation.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant Schema
    participant Context
    participant PanicUtil

    User->>Schema: Validate(data, valuePtr)
    Schema->>Context: Prepare context with valuePtr
    Schema->>Schema: Type assertion on valuePtr (safe check)
    alt Type assertion fails
        Schema->>PanicUtil: Panicf("Type cast error...", context info)
        PanicUtil-->>Schema: Panic triggered
    else Type assertion succeeds
        Schema->>Schema: Continue validation logic
    end
    Schema-->>User: Validation result or panic
Loading

Possibly related PRs

  • Oudwins/zog#141: Adds explicit type assertion checks with detailed panic messages in the process and validate methods of Custom[T], directly enhancing robustness in the same file.
  • Oudwins/zog#153: Introduces explicit type assertion checks and replaces direct panics with centralized panic calls in custom.go, closely related in error handling improvements.
  • Oudwins/zog#81: Refactors schema methods to use a unified SchemaCtx context and modifies method signatures, improving context handling and error reporting in related areas.

Poem

In fields of code where schemas grow,
A rabbit hops where types must show.
No more panics in the dark—
Now errors sing with context, stark!
With pointers safe and docs anew,
This bunny’s proud of what we do.
🐇✨


📜 Recent review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 0867de9 and 57f1f2a.

📒 Files selected for processing (1)
  • docs/docs/core-design-decisions.md (1 hunks)

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
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@cloudflare-workers-and-pages
Copy link

cloudflare-workers-and-pages bot commented May 3, 2025

Deploying zog with  Cloudflare Pages  Cloudflare Pages

Latest commit: 57f1f2a
Status:⚡️  Build in progress...

View logs

Copy link
Contributor

@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: 4

🧹 Nitpick comments (4)
struct.go (1)

167-167: Consider updating this panic to match the new pattern

This panic message could benefit from the same improvements applied at line 103 - using p.Panicf with the predefined constant and including context information. This would ensure consistency in error reporting throughout the codebase.

-			panic(fmt.Sprintf("Struct is missing expected schema key: %s", key))
+			p.Panicf(p.PanicMissingStructField, ctx.String(), key)
preprocess.go (1)

52-53: Consider standardizing this panic message as well

While you've improved type assertion error messages, this panic message for incompatible types still uses a direct panic(fmt.Sprintf(...)) call rather than the new p.Panicf function with a standardized message constant.

Consider standardizing this panic message by creating a constant in internals/panics.go and using p.Panicf:

-    panic(fmt.Sprintf("Preprocessed should be passed in schema.Validate() a value pointer that is compatible with its returned type T. Either *T or **T. Got %T", v))
+    p.Panicf(p.PanicIncompatiblePreprocessType, v)

You would need to add the constant to internals/panics.go:

const PanicIncompatiblePreprocessType = "Zog Panic: Type Compatibility Error\nPreprocessed should be passed in schema.Validate() a value pointer that is compatible with its returned type T. Either *T or **T. Got %T\nFor more information see: https://zog.dev/panics#type-cast-errors"
docs/docs/panics.md (1)

1-140: Well-structured documentation that clearly explains panic scenarios

The new documentation thoroughly explains when and why the library panics, with clear examples for different scenarios. This will be very helpful for users debugging issues.

The documentation provides comprehensive coverage of panic scenarios with practical examples and solutions.

Consider these minor grammar improvements for better readability:

  • Line 14: Add a comma after "In practice this means that" and after "but"
  • Line 14: Add a comma after "Most of the time"
  • Line 80: Add a determiner before "Same thing will happen"
-In practice this means that Zog will never panic if the input data is wrong but it will panic if you configure it wrong. Most of the time "configured it wrong" means that you have made a mistake in your schema definition which puts Zog into an invalid state and results in a schema that can never succeed.
+In practice, this means that Zog will never panic if the input data is wrong, but it will panic if you configure it wrong. Most of the time, "configured it wrong" means that you have made a mistake in your schema definition which puts Zog into an invalid state and results in a schema that can never succeed.
-Same thing will happen if you incorrectly set the type in a z.Custom schema:
+The same thing will happen if you incorrectly set the type in a z.Custom schema:
🧰 Tools
🪛 LanguageTool

[uncategorized] ~14-~14: A comma might be missing here.
Context: ... fundamental assumptions is broken. In practice this means that Zog will never panic if...

(AI_EN_LECTOR_MISSING_PUNCTUATION_COMMA)


[uncategorized] ~14-~14: Use a comma before ‘but’ if it connects two independent clauses (unless they are closely connected and short).
Context: ...l never panic if the input data is wrong but it will panic if you configure it wrong...

(COMMA_COMPOUND_SENTENCE)


[uncategorized] ~14-~14: A comma might be missing here.
Context: ... if you configure it wrong. Most of the time "configured it wrong" means that you ha...

(AI_EN_LECTOR_MISSING_PUNCTUATION_COMMA)


[uncategorized] ~80-~80: A determiner appears to be missing. Consider inserting it.
Context: ... but the value is of type MyString ``` Same thing will happen if you incorrectly se...

(AI_EN_LECTOR_MISSING_DETERMINER)

internals/panics.go (1)

1-14: Consider adding documentation comments for exported identifiers

The constants and function are exported and should have documentation comments that explain their purpose and usage.

Consider adding documentation comments for the exported identifiers:

+// PanicTypeCast is the format string for panics caused by type assertion failures on value pointers
const (
	PanicTypeCast           = "Zog Panic: Type Cast Error\n Current context: %s\n Expected valPtr type to correspond with type defined in schema. But it does not. Expected type: *%T, got: %T\nFor more information see: https://zog.dev/panics#type-cast-errors"
	PanicTypeCastCoercer    = "Zog Panic: Type Cast Error\n Current context: %s\n Expected coercer return value to correspond with type defined in schema. But it does not. Expected type: *%T, got: %T\nFor more information see: https://zog.dev/panics#type-cast-errors"
	PanicMissingStructField = "Zog Panic: Struct Schema Definition Error\n Current context: %s\n Provided struct is missing expected schema key: %s.\n This means you have made a mistake in your schema definition.\nFor more information see: https://zog.dev/panics#schema-definition-errors"
)

+// Panicf formats a panic message using fmt.Sprintf and triggers a panic with the resulting message
func Panicf(format string, args ...any) {
	panic(fmt.Sprintf(format, args...))
}
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 193c23c and 0867de9.

📒 Files selected for processing (10)
  • custom.go (2 hunks)
  • docs/docs/core-design-decisions.md (1 hunks)
  • docs/docs/panics.md (1 hunks)
  • internals/contexts.go (2 hunks)
  • internals/panics.go (1 hunks)
  • internals/utils.go (1 hunks)
  • preprocess.go (1 hunks)
  • struct.go (1 hunks)
  • struct_validate_test.go (1 hunks)
  • zogSchema.go (3 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (3)
struct.go (1)
internals/panics.go (2)
  • Panicf (11-13)
  • PanicMissingStructField (8-8)
internals/contexts.go (1)
internals/utils.go (1)
  • SafeString (10-22)
preprocess.go (1)
internals/panics.go (2)
  • Panicf (11-13)
  • PanicTypeCast (6-6)
🪛 LanguageTool
docs/docs/panics.md

[uncategorized] ~14-~14: A comma might be missing here.
Context: ... fundamental assumptions is broken. In practice this means that Zog will never panic if...

(AI_EN_LECTOR_MISSING_PUNCTUATION_COMMA)


[uncategorized] ~14-~14: Use a comma before ‘but’ if it connects two independent clauses (unless they are closely connected and short).
Context: ...l never panic if the input data is wrong but it will panic if you configure it wrong...

(COMMA_COMPOUND_SENTENCE)


[uncategorized] ~14-~14: A comma might be missing here.
Context: ... if you configure it wrong. Most of the time "configured it wrong" means that you ha...

(AI_EN_LECTOR_MISSING_PUNCTUATION_COMMA)


[uncategorized] ~80-~80: A determiner appears to be missing. Consider inserting it.
Context: ... but the value is of type MyString ``` Same thing will happen if you incorrectly se...

(AI_EN_LECTOR_MISSING_DETERMINER)

⏰ Context from checks skipped due to timeout of 90000ms (1)
  • GitHub Check: Cloudflare Pages
🔇 Additional comments (9)
docs/docs/core-design-decisions.md (1)

15-15: Great documentation improvement!

Converting the plain text reference to a clickable link improves navigation and helps users find detailed information about panic scenarios more easily.

internals/contexts.go (1)

213-215: Excellent addition for improved error diagnostics!

The String() method provides a comprehensive string representation of SchemaCtx that will significantly improve panic messages, making them more informative and useful for debugging. The use of SafeString for handling potentially nil values is a good safety measure.

struct_validate_test.go (1)

219-232: Great test addition for validating panic behavior!

This test effectively verifies that the validation correctly panics when there's a mismatch between schema field type (string) and struct field type (int). It provides good coverage for the improved panic handling implemented in this PR.

struct.go (1)

103-103: Improved panic message with better diagnostics!

Using the centralized p.Panicf with the predefined panic message constant and including the context information via ctx.String() greatly improves the error diagnostics. The link to documentation in the panic message will help developers resolve issues more quickly.

internals/utils.go (1)

14-21: Robust & succinct – approved

The recursive dereference loop elegantly handles arbitrarily-nested pointers while short-circuiting on nil, resulting in predictable <nil> output for panic diagnostics. Nice touch!

zogSchema.go (1)

90-95: 👍 Good coercer-cast safeguard

Adding the checked assertion with a dedicated PanicTypeCastCoercer path uniformly enforces type safety after coercion. No further issues spotted here.

preprocess.go (1)

36-41: Improved type assertion safety with better error messaging

The updated code replaces a direct type assertion with a safe type assertion plus explicit error handling. When a type mismatch occurs, it now provides detailed diagnostic information through a standardized panic message.

This change correctly aligns with the PR's goal of providing better panic messages and improves type safety by explicitly handling type assertion failures.

internals/panics.go (2)

5-9: Well-designed panic constants with detailed diagnostic information

The panic message constants provide detailed diagnostic information, including the context, expected and actual types, and documentation links. This will make debugging much easier for users.

The panic message formatting is clear and includes all necessary details for effective debugging.


11-13: Clean utility function for standardized panic handling

The Panicf function centralizes panic formatting and invocation, ensuring consistency across the codebase.

This utility function will help maintain consistent panic handling throughout the library.

Comment on lines +79 to 84
ptr, ok := ctx.ValPtr.(*T)
if !ok {
p.Panicf(p.PanicTypeCast, ctx.String(), ctx.DType, ctx.ValPtr)
}
c.test.Func(ptr, ctx)
}
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

⚠️ Potential issue

Same nil-pointer hole exists during validation

c.test.Func(ptr, ctx) may dereference ptr. Mirror the safety guard suggested above:

 ptr, ok := ctx.ValPtr.(*T)
 if !ok {
     p.Panicf(p.PanicTypeCast, ctx.String(), ctx.DType, ctx.ValPtr)
 }
+if ptr == nil {
+    p.Panicf(p.PanicNilPointer, ctx.String(), ctx.DType, ctx.ValPtr)
+}
 c.test.Func(ptr, ctx)
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
ptr, ok := ctx.ValPtr.(*T)
if !ok {
p.Panicf(p.PanicTypeCast, ctx.String(), ctx.DType, ctx.ValPtr)
}
c.test.Func(ptr, ctx)
}
ptr, ok := ctx.ValPtr.(*T)
if !ok {
p.Panicf(p.PanicTypeCast, ctx.String(), ctx.DType, ctx.ValPtr)
}
if ptr == nil {
p.Panicf(p.PanicNilPointer, ctx.String(), ctx.DType, ctx.ValPtr)
}
c.test.Func(ptr, ctx)
}
🤖 Prompt for AI Agents (early access)
In custom.go around lines 79 to 84, the code calls c.test.Func(ptr, ctx) without checking if ptr is nil, which can cause a nil-pointer dereference. Add a nil check for ptr after the type assertion and before calling c.test.Func. If ptr is nil, handle it appropriately, such as by panicking or returning an error, to prevent unsafe dereferencing.

Comment on lines +51 to 56
ptr, ok := ctx.ValPtr.(*T)
if !ok {
p.Panicf(p.PanicTypeCast, ctx.String(), ctx.DType, ctx.ValPtr)
}
*ptr = d

Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

⚠️ Potential issue

Guard against nil destination pointers to avoid runtime panics

ok only guarantees that ctx.ValPtr is of type *T; it might still be a nil pointer.
Dereferencing it on the next line (*ptr = d) will trigger a panic: runtime error: invalid memory address if the caller passes nil.
Given these helpers are frequently reused by end-users, crashing the whole process contradicts the goal of the PR (better-controlled panics).

 ptr, ok := ctx.ValPtr.(*T)
 if !ok {
     p.Panicf(p.PanicTypeCast, ctx.String(), ctx.DType, ctx.ValPtr)
 }
+if ptr == nil {
+    // NB: add PanicNilPointer to internals/panics.go for consistency.
+    p.Panicf(p.PanicNilPointer, ctx.String(), ctx.DType, ctx.ValPtr)
+}
 *ptr = d

Adding the extra check keeps the invariant “a panic only occurs through Panicf with actionable diagnostics” intact and eliminates a blind spot that would surface as an unstructured Go panic.

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents (early access)
In custom.go around lines 51 to 56, the code checks if ctx.ValPtr is of type *T but does not verify if the pointer is nil before dereferencing it. To fix this, add a nil check for ptr after the type assertion and before dereferencing. If ptr is nil, invoke p.Panicf with appropriate diagnostic information to maintain controlled panics and avoid runtime panics caused by dereferencing nil pointers.

Comment on lines +56 to 60
destPtr, ok := ctx.ValPtr.(*T)
if !ok {
p.Panicf(p.PanicTypeCast, ctx.String(), ctx.DType, ctx.ValPtr)
}

Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

⚠️ Potential issue

Handle nil destPtr before dereferencing

*destPtr = *defaultVal (and several subsequent writes) assume a non-nil pointer.
Insert the defensive check used for type-mismatch to also cover nil pointers:

 destPtr, ok := ctx.ValPtr.(*T)
 if !ok {
     p.Panicf(p.PanicTypeCast, ctx.String(), ctx.DType, ctx.ValPtr)
 }
+if destPtr == nil {
+    p.Panicf(p.PanicNilPointer, ctx.String(), ctx.DType, ctx.ValPtr)
+}
🤖 Prompt for AI Agents (early access)
In zogSchema.go around lines 56 to 60, before dereferencing destPtr, add a check to ensure destPtr is not nil, similar to the existing type assertion check. If destPtr is nil, call p.Panicf with appropriate arguments to handle the error defensively and prevent nil pointer dereference.

Comment on lines +113 to +116
valPtr, ok := ctx.ValPtr.(*T)
if !ok {
p.Panicf(p.PanicTypeCast, ctx.String(), ctx.DType, ctx.ValPtr)
}
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

⚠️ Potential issue

Parallel nil-pointer risk during validation

primitiveValidation dereferences valPtr multiple times. Replicate the nil-pointer guard:

 valPtr, ok := ctx.ValPtr.(*T)
 if !ok {
     p.Panicf(p.PanicTypeCast, ctx.String(), ctx.DType, ctx.ValPtr)
 }
+if valPtr == nil {
+    p.Panicf(p.PanicNilPointer, ctx.String(), ctx.DType, ctx.ValPtr)
+}
🤖 Prompt for AI Agents (early access)
In zogSchema.go around lines 113 to 116, the code casts ctx.ValPtr to *T but does not check if valPtr is nil before dereferencing it multiple times later in primitiveValidation. Add a nil-pointer check after the type assertion to ensure valPtr is not nil, and handle the nil case appropriately to prevent runtime panics during validation.

@Oudwins Oudwins merged commit f605689 into master May 3, 2025
8 of 10 checks passed
Oudwins added a commit that referenced this pull request Oct 3, 2025
* feat: provide better panic msgs and docs

* fix: docs link
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.

1 participant