Troubleshooting
5 minute read
Common issues, solutions, and debugging tips for the validation package.
Validation Not Running
Issue: Validation passes when it should fail
Symptom:
type User struct {
Email string `validate:"required,email"`
}
user := User{Email: ""} // Should fail
err := validation.Validate(ctx, &user) // err is nil (unexpected)
Possible Causes:
- Struct tags not being checked
Check if a higher-priority strategy is being used:
func (u *User) Validate() error {
return nil // This runs instead of tags
}
Solution: Remove interface method or use WithStrategy:
err := validation.Validate(ctx, &user,
validation.WithStrategy(validation.StrategyTags),
)
- Wrong tag name
// Wrong
Email string `validation:"required"` // Should be "validate"
// Correct
Email string `validate:"required"`
- Validating value instead of pointer
// May not work with pointer receivers
user := User{} // value
user.Validate() // Method might not be found
// Use pointer
user := &User{} // pointer
validation.Validate(ctx, user)
Partial Validation Issues
Issue: Required fields failing in PATCH requests
Symptom:
type UpdateUser struct {
Email string `validate:"required,email"`
}
// PATCH with only age
err := validation.ValidatePartial(ctx, &req, presence)
// Error: email is required (but it wasn't provided)
Solution: Use omitempty instead of required for PATCH:
type UpdateUser struct {
Email string `validate:"omitempty,email"` // Not "required"
}
Issue: Presence map not being respected
Symptom:
presence, _ := validation.ComputePresence(rawJSON)
err := validation.Validate(ctx, &req, // Missing WithPresence!
validation.WithPartial(true),
)
Solution: Always pass presence map:
err := validation.Validate(ctx, &req,
validation.WithPartial(true),
validation.WithPresence(presence), // Add this
)
Custom Validation Issues
Issue: Custom tag not working
Symptom:
validator := validation.MustNew(
validation.WithCustomTag("phone", phoneValidator),
)
type User struct {
Phone string `validate:"phone"` // Not recognized
}
Possible Causes:
- Tag registered on wrong validator
// Registered on custom validator
validator := validation.MustNew(
validation.WithCustomTag("phone", phoneValidator),
)
// But using package-level function (different validator)
validation.Validate(ctx, &user) // Doesn't have custom tag
Solution: Use the same validator:
validator.Validate(ctx, &user) // Use custom validator
- Tag function signature wrong
// Wrong
func phoneValidator(val string) bool { ... }
// Correct
func phoneValidator(fl validator.FieldLevel) bool { ... }
Issue: ValidateContext not being called
Symptom:
func (u *User) ValidateContext(ctx context.Context) error {
fmt.Println("Never prints")
return nil
}
Possible Causes:
- Wrong receiver type
// Method defined on value
func (u User) ValidateContext(ctx context.Context) error { ... }
// But validating pointer
user := &User{}
validation.Validate(ctx, user) // Method not found
Solution: Use pointer receiver:
func (u *User) ValidateContext(ctx context.Context) error { ... }
- Struct tags have priority
If auto-selection chooses tags, interface method isn’t called.
Solution: Explicitly use interface strategy:
validation.Validate(ctx, &user,
validation.WithStrategy(validation.StrategyInterface),
)
Error Handling Issues
Issue: Can’t access field errors
Symptom:
err := validation.Validate(ctx, &user)
// How do I get field-level errors?
Solution: Use errors.As:
var verr *validation.Error
if errors.As(err, &verr) {
for _, fieldErr := range verr.Fields {
fmt.Printf("%s: %s\n", fieldErr.Path, fieldErr.Message)
}
}
Issue: Sensitive data visible in errors
Symptom:
// Error message contains password value
email: invalid email (value: "password123")
Solution: Use redactor:
validator := validation.MustNew(
validation.WithRedactor(func(path string) bool {
return strings.Contains(path, "password")
}),
)
Performance Issues
Issue: Validation is slow
Possible Causes:
- Creating validator on every request
// Bad - creates validator every time
func Handler(w http.ResponseWriter, r *http.Request) {
validator := validation.MustNew(...) // Slow
validator.Validate(ctx, &req)
}
Solution: Create once, reuse:
var validator = validation.MustNew(...)
func Handler(w http.ResponseWriter, r *http.Request) {
validator.Validate(ctx, &req) // Fast
}
- JSON Schema not cached
func (u User) JSONSchema() (id, schema string) {
return "", `{...}` // Empty ID = no caching
}
Solution: Use stable ID:
func (u User) JSONSchema() (id, schema string) {
return "user-v1", `{...}` // Cached
}
- Expensive ValidateContext
func (u *User) ValidateContext(ctx context.Context) error {
// Expensive operation on every validation
return checkWithExternalAPI(u.Email)
}
Solution: Optimize or cache:
func (u *User) ValidateContext(ctx context.Context) error {
// Fast checks first
if !basicValidation(u.Email) {
return errors.New("invalid format")
}
// Expensive check last
return checkWithExternalAPI(u.Email)
}
JSON Schema Issues
Issue: Schema validation not working
Symptom:
func (u User) JSONSchema() (id, schema string) {
return "user-v1", `{...}`
}
// But validation doesn't use schema
Possible Causes:
- Higher priority strategy exists
type User struct {
Email string `validate:"email"` // Tags have higher priority
}
func (u User) JSONSchema() (id, schema string) {
return "user-v1", `{...}` // Not used
}
Solution: Use explicit strategy:
validation.Validate(ctx, &user,
validation.WithStrategy(validation.StrategyJSONSchema),
)
- Invalid JSON Schema
func (u User) JSONSchema() (id, schema string) {
return "user-v1", `{ invalid json }` // Parse error
}
Solution: Validate schema syntax:
// Use online validator: https://www.jsonschemavalidator.net/
Context Issues
Issue: Context values not available
Symptom:
func (u *User) ValidateContext(ctx context.Context) error {
db := ctx.Value("db") // db is nil
// ...
}
Solution: Ensure values are in context:
ctx = context.WithValue(ctx, "db", db)
err := validation.Validate(ctx, &user)
Issue: Wrong context being used
Symptom:
err := validation.Validate(ctx1, &user,
validation.WithContext(ctx2), // Overrides ctx1
)
Solution: Don’t use WithContext unless necessary:
// Just pass the right context
err := validation.Validate(correctCtx, &user)
Module and Import Issues
Issue: Cannot find module
go: finding module for package rivaas.dev/validation
Solution:
go mod tidy
go get rivaas.dev/validation
Issue: Version conflicts
require rivaas.dev/validation v1.0.0
// +incompatible
Solution: Update to compatible version:
go get rivaas.dev/validation@latest
go mod tidy
Common Error Messages
“cannot validate nil value”
Cause: Passing nil to Validate:
var user *User
validation.Validate(ctx, user) // Error: cannot validate nil value
Solution: Ensure value is not nil:
user := &User{Email: "test@example.com"}
validation.Validate(ctx, user)
“cannot validate invalid value”
Cause: Passing invalid reflect.Value:
var v interface{}
validation.Validate(ctx, v) // Error: cannot validate invalid value
Solution: Pass actual struct:
user := &User{}
validation.Validate(ctx, user)
“unknown validation strategy”
Cause: Invalid strategy value:
validation.Validate(ctx, &user,
validation.WithStrategy(999), // Invalid
)
Solution: Use valid strategy constants:
validation.Validate(ctx, &user,
validation.WithStrategy(validation.StrategyTags),
)
Debugging Tips
1. Check which strategy is being used
// Temporarily force each strategy to see which works
strategies := []validation.Strategy{
validation.StrategyInterface,
validation.StrategyTags,
validation.StrategyJSONSchema,
}
for _, strategy := range strategies {
err := validation.Validate(ctx, &user,
validation.WithStrategy(strategy),
)
fmt.Printf("%v: %v\n", strategy, err)
}
2. Enable all error reporting
err := validation.Validate(ctx, &user,
validation.WithMaxErrors(0), // Unlimited
)
3. Check struct tags
import "reflect"
t := reflect.TypeOf(User{})
for i := 0; i < t.NumField(); i++ {
field := t.Field(i)
fmt.Printf("%s: %s\n", field.Name, field.Tag.Get("validate"))
}
4. Test interface implementation
var _ validation.ValidatorInterface = (*User)(nil) // Compile-time check
var _ validation.ValidatorWithContext = (*User)(nil)
var _ validation.JSONSchemaProvider = (*User)(nil)
Getting Help
If you’re still stuck:
- Check documentation: User Guide
- Review examples: Examples
- Check pkg.go.dev: API Documentation
- GitHub Issues: Report a bug
- Discussions: Ask a question
Next Steps
- API Reference - Core types and functions
- Options - Configuration options
- User Guide - Learning tutorials
Feedback
Was this page helpful?
Glad to hear it! Please tell us how we can improve.
Sorry to hear that. Please tell us how we can improve.