Skip to content

feat!: removing field key and invalid type schema panics - #229

Merged
Oudwins merged 4 commits into
masterfrom
refactor/invalid-type-panics
Jun 16, 2026
Merged

feat!: removing field key and invalid type schema panics#229
Oudwins merged 4 commits into
masterfrom
refactor/invalid-type-panics

Conversation

@Oudwins

@Oudwins Oudwins commented Jun 8, 2026

Copy link
Copy Markdown
Owner

Summary by CodeRabbit

  • Bug Fixes

    • Parsing and validation no longer panic on type mismatches across primitives, pointers, slices, maps, structs, boxed/custom/any, and preprocessing. Instead, the operations record an error and return early so execution can continue safely.
  • New Features

    • Added consistent error reporting for invalid input types and missing struct fields, with new dedicated issue codes/messages.
  • Tests

    • Added/updated tests to verify invalid-type handling and missing-field behavior (including nil and non-matching input types).

@coderabbitai

coderabbitai Bot commented Jun 8, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Walkthrough

Schema parsing and validation now handle type mismatches gracefully by recording InvalidType and MissingField issues instead of panicking. The ZogIssues interface is replaced with a concrete ErrsList type. New standardized issue codes and error formatters enable consistent error reporting across all schema types.

Changes

Type validation error handling

Layer / File(s) Summary
Error collection infrastructure and execution context
pkgs/internals/Issues.go, pkgs/internals/contexts.go, pkgs/internals/panics.go
ZogIssues interface replaced with concrete ErrsList type using pool-based allocation. ExecCtx.Errors field and NewExecCtx signature updated to store and accept *ErrsList. Panic constant PanicTypeCast removed.
Issue codes, error formatting, and schema helpers
zconst/consts.go, pkgs/internals/contexts.go
New exported constants IssueCodeInvalidType and IssueCodeMissingField. Error formatting helpers ErrorInvalidTypeMessage and ErrorMissingStructField added to zconst. SchemaCtx gains IssueFromInvalidType and IssueFromMissingStructField methods that construct standardized *ZogIssue values.
Test context factory
pkgs/internals/tutils/fakeContext.go
New FakeContextFromValue helper creates execution and schema contexts from input values and schema type, supporting validation test cases for invalid types.
Schema type validation across implementations
zogSchema.go, any.go, custom.go, boxedSchema.go, maps.go, pointers.go, slices.go, struct.go, preprocess.go
All schema handlers now validate pointer/value types before dereferencing. Type mismatches record InvalidType issues via ctx.ExecCtx.AddIssue(ctx.IssueFromInvalidType(...)) and return early. Struct parser records MissingField issues when schema keys don't match destination fields and continues processing.
Test updates for issue-based error reporting
boolean_test.go, boolean_validate_test.go, struct_test.go, struct_validate_test.go, pointers_validate_test.go
New tests TestBoolInvalidType and TestBoolValidateInvalidType assert invalid-type rejection. TestStructPanicsOnSchemaMismatch updated to assert MissingField issues instead of panics. TestValidateStructInvalidSchema removed. TestValidatePtrPrimitive updated to expect InvalidType issue code instead of panic.

Sequence Diagram(s)

sequenceDiagram
  participant Caller
  participant Schema as Schema Handler
  participant ValidateType as Type Check
  participant IssueBuilder as SchemaCtx
  participant ExecCtx
  participant IssueList as ZogIssueList
  
  Caller->>Schema: Parse/Validate with mismatched pointer type
  Schema->>ValidateType: Validate ctx.ValPtr type
  alt Type mismatch detected
    ValidateType->>IssueBuilder: IssueFromInvalidType(expected, received, operation)
    IssueBuilder->>ExecCtx: AddIssue(issue with InvalidType code)
    ExecCtx->>IssueList: Append issue
    IssueBuilder-->>Schema: return *ZogIssue
    Schema->>Caller: Return early (no panic)
  else Type matches
    ValidateType->>Schema: Continue
    Schema->>Caller: Process schema normally
  end
  Caller->>Caller: Check error list for InvalidType code
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

  • Oudwins/zog#214: Both PRs modify AnySchema.process and AnySchema.validate around ctx.ValPtr pointer validation; this PR changes from panic-based handling to issue recording for invalid types.
  • Oudwins/zog#153: Related type-assertion and pointer-mismatch handling in custom schema implementations (custom.go); both PRs address similar type-cast failure scenarios.
  • Oudwins/zog#141: Both PRs modify Custom[T].process and Custom[T].validate execution paths; this PR converts those paths from panic-based to issue-based error handling.

Poem

🐰 Panics are out, issues hop in,
I sniff the types with careful grin.
No more crashes, just a gentle note,
Errors recorded in the issue tote.
Hooray — tests pass as I nibble a mote.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 7.69% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title accurately describes the main objective: removing panics related to invalid type schemas and missing struct field keys. The changes systematically replace panic-based failures with issue reporting across multiple schema processors.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch refactor/invalid-type-panics

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.

@Oudwins
Oudwins marked this pull request as ready for review June 8, 2026 06:38
@greptile-apps

greptile-apps Bot commented Jun 8, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR replaces hard panics on type mismatches and missing struct fields with structured ZogIssue errors, allowing parsing and validation to continue gracefully instead of crashing. New error codes (invalid_type, missing_field) and two helper constructors are introduced alongside updated tests.

  • struct.go validate() at line 195 still panics when a schema key is missing from the destination struct — the process() path was correctly migrated but validate() was missed, and the test that asserted the panic was deleted without a replacement.
  • Every other schema (any, custom, boxed, maps, slices, pointers, preprocess) was correctly migrated to ctx.ExecCtx.AddIssue with proper formatter invocation.
  • primitiveParsing in zogSchema.go uses ctx.Errors.Add(...) directly instead of ctx.ExecCtx.AddIssue(...), so the issue formatter is never called and Message will always be empty for primitive parse-time type mismatches.

Confidence Score: 3/5

Not safe to merge as-is: the validate() path in struct.go still panics when the schema shape references a field absent from the destination struct, and the test that would have caught this regression was deleted.

The validate() branch of StructSchema retained its panic for missing fields while process() was correctly migrated. Callers using schema.Validate() with a mismatched struct definition will still get an unrecovered runtime panic — the exact class of crash this PR set out to eliminate.

struct.go (validate() missing-field panic at line 195) and struct_validate_test.go (the covering test was removed without replacement)

Important Files Changed

Filename Overview
struct.go process() migrated from panic to ctx.AddIssue for both invalid-type and missing-field cases, but validate() at line 195 still panics on missing struct keys — a live regression since the corresponding test was deleted.
struct_validate_test.go TestValidateStructInvalidSchema was deleted (it was asserting a panic) but no replacement test was added for the validate() missing-field path, leaving the surviving panic at line 195 uncovered.
zogSchema.go primitiveValidation correctly migrated to ctx.ExecCtx.AddIssue; primitiveParsing still uses ctx.Errors.Add directly, bypassing the formatter (issue Message will always be empty for parse-time type mismatches).
pkgs/internals/contexts.go Added IssueFromInvalidType and IssueFromMissingStructField helpers; ExecCtx.Errors type narrowed from interface to *ErrsList; ZogIssues interface removed.
zconst/consts.go Added IssueCodeInvalidType and IssueCodeMissingField constants plus two error message helper functions; comment on IssueCodeInvalidType mentions 'boolean' specifically but the code applies to all type mismatches.
boolean_test.go New TestBoolInvalidType test covers process() with non-*bool inputs; assert.Equal arguments are in wrong order (actual/expected swapped).
boolean_validate_test.go New TestBoolValidateInvalidType test covers validate() with non-*bool inputs; assert.Equal argument order is reversed (same issue as boolean_test.go).

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[schema.process / schema.validate] --> B{ValPtr type check}
    B -- ok --> C[Normal processing]
    B -- not ok --> D{Which path?}

    D -- complex schemas any/maps/slices/struct/boxed/custom/preprocess --> E[ctx.ExecCtx.AddIssue IssueFromInvalidType]
    D -- primitiveParsing --> F[ctx.Errors.Add - Formatter bypassed]
    D -- primitiveValidation --> E

    E --> G[ExecCtx.AddIssue calls Fmter sets Message]
    G --> H[ErrsList.Add returns to caller]
    F --> H

    I[struct.process missing field] --> J[ctx.AddIssue IssueFromMissingStructField OK]
    K[struct.validate missing field] --> L[panic - Still panics!]
Loading
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
flowchart TD
    A[schema.process / schema.validate] --> B{ValPtr type check}
    B -- ok --> C[Normal processing]
    B -- not ok --> D{Which path?}

    D -- complex schemas any/maps/slices/struct/boxed/custom/preprocess --> E[ctx.ExecCtx.AddIssue IssueFromInvalidType]
    D -- primitiveParsing --> F[ctx.Errors.Add - Formatter bypassed]
    D -- primitiveValidation --> E

    E --> G[ExecCtx.AddIssue calls Fmter sets Message]
    G --> H[ErrsList.Add returns to caller]
    F --> H

    I[struct.process missing field] --> J[ctx.AddIssue IssueFromMissingStructField OK]
    K[struct.validate missing field] --> L[panic - Still panics!]
Loading

Comments Outside Diff (1)

  1. struct.go, line 195 (link)

    P1 Missing-field panic survives in validate() path

    process() was migrated from Panicf(PanicMissingStructField, ...) to ctx.AddIssue(ctx.IssueFromMissingStructField(key)), but the equivalent check in validate() still calls panic(...). The test TestValidateStructInvalidSchema that documented this panic was removed in struct_validate_test.go, so nothing now catches the regression. Any caller that uses schema.Validate() with a Shape key not present in the destination struct will still get a hard runtime panic instead of a structured ZogIssue.

Reviews (3): Last reviewed commit: "fix: review" | Re-trigger Greptile

Comment thread zogSchema.go
Comment thread zogSchema.go
Comment thread zconst/consts.go

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 5

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
struct.go (1)

174-174: ⚠️ Potential issue | 🔴 Critical | ⚡ Quick win

Inconsistent error handling: validate still panics on missing struct field.

Line 109-110 in the process function correctly records a MissingStructField issue and continues when a schema key doesn't match a struct field. However, line 174 in the validate function still panics for the same condition. This creates inconsistent behavior: users calling Parse get graceful error collection, while users calling Validate get a panic.

🐛 Proposed fix to record issue instead of panicking
 	fieldMeta, ok := refVal.Type().FieldByName(key)
 	if !ok {
-		panic(fmt.Sprintf("Struct is missing expected schema key: %s", key))
+		ctx.AddIssue(ctx.IssueFromMissingStructField(key))
+		continue
 	}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@struct.go` at line 174, validate currently panics when a schema key is
missing from the struct (panic(fmt.Sprintf("Struct is missing expected schema
key: %s", key))) causing inconsistent behavior with process/Parse which records
a MissingStructField issue; change validate to record the same
MissingStructField issue (using the same issue type/name used in process) for
the missing key (include the key value and context like struct name) and
return/continue gracefully instead of panicking so Validate mirrors Parse’s
error-collection behavior.
🧹 Nitpick comments (1)
struct_test.go (1)

274-274: ⚡ Quick win

Rename test to reflect non-panic behavior.

TestStructPanicsOnSchemaMismatch now validates recorded MissingField issues rather than panic behavior, so the name is stale and misleading.

Proposed rename
-func TestStructPanicsOnSchemaMismatch(t *testing.T) {
+func TestStructReportsMissingFieldOnSchemaMismatch(t *testing.T) {
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@struct_test.go` at line 274, Rename the test function
TestStructPanicsOnSchemaMismatch to a name that reflects its current behavior
(e.g., TestStructRecordsMissingFieldOnSchemaMismatch or
TestStructReportsMissingFieldOnSchemaMismatch) and update any
references/imports/usages accordingly; locate the function declaration
TestStructPanicsOnSchemaMismatch in struct_test.go and change the function name
and any occurrences in comments or test lists so the name matches that the test
asserts recorded MissingField issues rather than expecting a panic.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@boolean_test.go`:
- Around line 530-532: Add a guard asserting the issue list is non-empty before
indexing errs.List[0]: ensure you first assert that errs.List is not nil and has
length > 0 (e.g., using assert.NotEmpty or assert.Len on errs.List) and only
then verify errs.List[0].Code equals zconst.IssueCodeInvalidType so the test
cannot panic when no issues are recorded.

In `@boolean_validate_test.go`:
- Around line 401-403: The test reads errs.List[0] without ensuring the slice
has elements; replace the current nil-check (assert.NotNil(t, errs.List)) with a
non-empty assertion such as assert.NotEmpty(t, errs.List) or add
assert.Greater(t, len(errs.List), 0) before the access so the test fails clearly
if no issues exist; update the assertions around errs.List and the subsequent
assert.Equal referencing errs.List[0].Code accordingly.

In `@pkgs/internals/contexts.go`:
- Around line 46-49: NewExecCtx can accept a nil errs and later dereferences
c.Errors in methods like HasErrored and AddIssue; fix by guarding inside
NewExecCtx (and similarly in other constructors if present) to ensure c.Errors
is never nil: if errs == nil create a new ErrsList instance and assign it to
c.Errors before returning the pooled ExecCtx (refer to NewExecCtx, ExecCtxPool,
ExecCtx, ErrsList, and the methods HasErrored/AddIssue to locate usage).

In `@struct_test.go`:
- Around line 294-295: The test currently asserts only that errs is not nil then
immediately indexes errs[0], which can panic if errs is an empty slice; update
the assertions around the errs variable (in struct_test.go where errs is
checked) to ensure the slice is non-empty before indexing — e.g., replace or
augment assert.NotNil(t, errs) with an assertion that errs has length > 0
(assert.NotEmpty or assert.Greater(len(errs), 0)) prior to asserting
errs[0].Code equals zconst.IssueCodeMissingField.

In `@zogSchema.go`:
- Around line 60-61: Replace direct calls to ctx.Errors.Add(...) with the
standard wrapper ctx.AddIssue(...); specifically change uses of
ctx.Errors.Add(ctx.IssueFromInvalidType("pointer matching primitive schema
type", ctx.ValPtr, "parsing a primitive schema")) and the similar call at the
other occurrence to ctx.AddIssue(ctx.IssueFromInvalidType(...)). This keeps
behavior identical but restores consistency with other call sites that use
ctx.AddIssue and aligns with functions/methods like ctx.IssueFromInvalidType and
ctx.AddIssue used elsewhere in this module.

---

Outside diff comments:
In `@struct.go`:
- Line 174: validate currently panics when a schema key is missing from the
struct (panic(fmt.Sprintf("Struct is missing expected schema key: %s", key)))
causing inconsistent behavior with process/Parse which records a
MissingStructField issue; change validate to record the same MissingStructField
issue (using the same issue type/name used in process) for the missing key
(include the key value and context like struct name) and return/continue
gracefully instead of panicking so Validate mirrors Parse’s error-collection
behavior.

---

Nitpick comments:
In `@struct_test.go`:
- Line 274: Rename the test function TestStructPanicsOnSchemaMismatch to a name
that reflects its current behavior (e.g.,
TestStructRecordsMissingFieldOnSchemaMismatch or
TestStructReportsMissingFieldOnSchemaMismatch) and update any
references/imports/usages accordingly; locate the function declaration
TestStructPanicsOnSchemaMismatch in struct_test.go and change the function name
and any occurrences in comments or test lists so the name matches that the test
asserts recorded MissingField issues rather than expecting a panic.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 66dd712f-ac95-4465-9d68-5dc2fbe846ab

📥 Commits

Reviewing files that changed from the base of the PR and between c32cea0 and 57771c4.

📒 Files selected for processing (15)
  • any.go
  • boolean_test.go
  • boolean_validate_test.go
  • custom.go
  • maps.go
  • pkgs/internals/Issues.go
  • pkgs/internals/contexts.go
  • pkgs/internals/panics.go
  • pkgs/internals/tutils/fakeContext.go
  • preprocess.go
  • struct.go
  • struct_test.go
  • struct_validate_test.go
  • zconst/consts.go
  • zogSchema.go
💤 Files with no reviewable changes (2)
  • struct_validate_test.go
  • pkgs/internals/Issues.go

Comment thread boolean_test.go
Comment on lines +530 to +532
assert.NotNil(t, errs.List)
assert.Equal(t, errs.List[0].Code, zconst.IssueCodeInvalidType)

@coderabbitai coderabbitai Bot Jun 8, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Guard against empty issue lists before indexing.

At Line 531, errs.List[0] is accessed without asserting non-empty; this can panic and obscure failures when no issues are recorded.

Proposed fix
 		schema.process(ctx)
-		assert.NotNil(t, errs.List)
-		assert.Equal(t, errs.List[0].Code, zconst.IssueCodeInvalidType)
+		assert.NotEmpty(t, errs.List)
+		assert.Equal(t, zconst.IssueCodeInvalidType, errs.List[0].Code)
📝 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
assert.NotNil(t, errs.List)
assert.Equal(t, errs.List[0].Code, zconst.IssueCodeInvalidType)
assert.NotEmpty(t, errs.List)
assert.Equal(t, zconst.IssueCodeInvalidType, errs.List[0].Code)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@boolean_test.go` around lines 530 - 532, Add a guard asserting the issue list
is non-empty before indexing errs.List[0]: ensure you first assert that
errs.List is not nil and has length > 0 (e.g., using assert.NotEmpty or
assert.Len on errs.List) and only then verify errs.List[0].Code equals
zconst.IssueCodeInvalidType so the test cannot panic when no issues are
recorded.

@Oudwins Oudwins Jun 9, 2026

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

@CodeRabbit I don't write defensive code inside tests. Please remember that. its not the first time you suggest this stupid changes

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

@Oudwins, my apologies — I'll stop suggesting defensive guards in test code. Noted and remembered.

(ᵕ︵ᵕ)


✏️ Learnings added
Learnt from: Oudwins
Repo: Oudwins/zog PR: 229
File: boolean_test.go:530-532
Timestamp: 2026-06-09T06:24:52.565Z
Learning: In the `Oudwins/zog` repository, the author does not write defensive code inside tests. Do not suggest adding guards (e.g., asserting non-empty before indexing, nil checks, length checks) in test functions. Such suggestions are explicitly unwanted.

Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.

Comment thread boolean_validate_test.go
Comment on lines +46 to 49
func NewExecCtx(errs *ErrsList, fmter IssueFmtFunc) *ExecCtx {
c := ExecCtxPool.Get().(*ExecCtx)
c.Fmter = fmter
c.Errors = errs

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Guard against nil errs in NewExecCtx.

Line 46 now accepts a nullable pointer, but Lines 63 and 86 dereference c.Errors unconditionally. A nil errs will panic on first HasErrored()/AddIssue() call.

Suggested fix
 func NewExecCtx(errs *ErrsList, fmter IssueFmtFunc) *ExecCtx {
+	if errs == nil {
+		errs = NewErrsList()
+	}
 	c := ExecCtxPool.Get().(*ExecCtx)
 	c.Fmter = fmter
 	c.Errors = errs
 	if c.m != nil {
 		clear(c.m)
 	}
 	return c
 }

Also applies to: 58-64, 82-87

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pkgs/internals/contexts.go` around lines 46 - 49, NewExecCtx can accept a nil
errs and later dereferences c.Errors in methods like HasErrored and AddIssue;
fix by guarding inside NewExecCtx (and similarly in other constructors if
present) to ensure c.Errors is never nil: if errs == nil create a new ErrsList
instance and assign it to c.Errors before returning the pooled ExecCtx (refer to
NewExecCtx, ExecCtxPool, ExecCtx, ErrsList, and the methods HasErrored/AddIssue
to locate usage).

Comment thread struct_test.go
Comment thread zogSchema.go
@Oudwins
Oudwins merged commit 9d196f8 into master Jun 16, 2026
14 of 15 checks passed

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
struct.go (1)

193-196: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

StructSchema.validate still panics on missing schema field; report issue instead.

At Line 195, panic(...) remains in the validate path for a missing destination field. process already records IssueFromMissingStructField; validate should follow the same non-panicking contract.

💡 Suggested fix
  fieldMeta, ok := refVal.Type().FieldByName(key)
  if !ok {
-   panic(fmt.Sprintf("Struct is missing expected schema key: %s", key))
+   ctx.AddIssue(ctx.IssueFromMissingStructField(key))
+   continue
  }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@struct.go` around lines 193 - 196, In the StructSchema.validate method where
FieldByName returns false for the key, replace the panic call with a
non-panicking error handling approach that records an
IssueFromMissingStructField issue, consistent with how the process method
already handles missing struct fields. This ensures validate follows a
consistent contract with process by reporting issues instead of panicking.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@pointers.go`:
- Around line 129-131: The call to destPtr.IsNil() on line 130 can panic when
destPtr is not a type that supports the IsNil method (such as when ctx.ValPtr is
a pointer to a non-pointer value like *int). Before calling destPtr.IsNil(), add
a guard that checks destPtr.Kind() to ensure it is a type that supports IsNil
(such as reflect.Ptr, reflect.Interface, reflect.Map, reflect.Slice,
reflect.Chan, or reflect.Func). If the kind check fails, emit an InvalidType
error and return early instead of proceeding to the IsNil call, preventing the
panic.

---

Outside diff comments:
In `@struct.go`:
- Around line 193-196: In the StructSchema.validate method where FieldByName
returns false for the key, replace the panic call with a non-panicking error
handling approach that records an IssueFromMissingStructField issue, consistent
with how the process method already handles missing struct fields. This ensures
validate follows a consistent contract with process by reporting issues instead
of panicking.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: f1f501b7-73f9-4f32-8fdb-991e1891827f

📥 Commits

Reviewing files that changed from the base of the PR and between 56c86ec and 3641ec9.

📒 Files selected for processing (10)
  • any.go
  • boxedSchema.go
  • custom.go
  • maps.go
  • pointers.go
  • pointers_validate_test.go
  • preprocess.go
  • slices.go
  • struct.go
  • zogSchema.go
🚧 Files skipped from review as they are similar to previous changes (3)
  • any.go
  • custom.go
  • zogSchema.go

Comment thread pointers.go
Comment on lines 129 to 131
destPtr := rv.Elem()
if !destPtr.IsValid() || destPtr.IsNil() {
if v.required != nil {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical | ⚡ Quick win

Guard destPtr.Kind() before IsNil() to avoid a remaining panic path.

At Line 130, destPtr.IsNil() can still panic when ctx.ValPtr is a pointer to a non-pointer value (e.g. *int). This path should emit InvalidType and return, not panic.

💡 Suggested fix
  destPtr := rv.Elem()
- if !destPtr.IsValid() || destPtr.IsNil() {
+ if !destPtr.IsValid() || destPtr.Kind() != reflect.Pointer {
+   ctx.ExecCtx.AddIssue(ctx.IssueFromInvalidType("pointer", ctx.ValPtr, "validating a pointer schema"))
+   return
+ }
+ if destPtr.IsNil() {
    if v.required != nil {
      // We set the destination type to the schema type because pointer doesn't have any issue messages. They pass through to the schema type
      ctx.AddIssue(ctx.IssueFromTest(v.required, ctx.Data).SetDType(v.schema.getType()))
    }
    return
  }
📝 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
destPtr := rv.Elem()
if !destPtr.IsValid() || destPtr.IsNil() {
if v.required != nil {
destPtr := rv.Elem()
if !destPtr.IsValid() || destPtr.Kind() != reflect.Pointer {
ctx.ExecCtx.AddIssue(ctx.IssueFromInvalidType("pointer", ctx.ValPtr, "validating a pointer schema"))
return
}
if destPtr.IsNil() {
if v.required != nil {
// We set the destination type to the schema type because pointer doesn't have any issue messages. They pass through to the schema type
ctx.AddIssue(ctx.IssueFromTest(v.required, ctx.Data).SetDType(v.schema.getType()))
}
return
}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pointers.go` around lines 129 - 131, The call to destPtr.IsNil() on line 130
can panic when destPtr is not a type that supports the IsNil method (such as
when ctx.ValPtr is a pointer to a non-pointer value like *int). Before calling
destPtr.IsNil(), add a guard that checks destPtr.Kind() to ensure it is a type
that supports IsNil (such as reflect.Ptr, reflect.Interface, reflect.Map,
reflect.Slice, reflect.Chan, or reflect.Func). If the kind check fails, emit an
InvalidType error and return early instead of proceeding to the IsNil call,
preventing the panic.

@Oudwins
Oudwins deleted the refactor/invalid-type-panics branch June 16, 2026 07:07
Oudwins added a commit that referenced this pull request Jul 5, 2026
…equired change to support union schema (#229)

* wp

* refactor!: remove panics from invalid types

* feat: add zog skill to repo

* fix: review
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