PluginBench
Skill
Pass
Audit score 90

safe-action-validation-errors

next-safe-action/skills

How to install safe-action-validation-errors

npx skills add https://github.com/next-safe-action/skills --skill safe-action-validation-errors
Claude Code
Cursor
Windsurf
Cline
Full instructions (SKILL.md)

Source of truth, from next-safe-action/skills.


name: safe-action-validation-errors description: Use when working with validation errors -- returnValidationErrors, formatted vs flattened shapes, custom validation error shapes, throwValidationErrors, or displaying field-level and form-level errors

next-safe-action Validation Errors

Two Sources of Validation Errors

  1. Schema validation — automatic when input doesn't match .inputSchema()
  2. Manual validation — via returnValidationErrors() in server code (e.g., "email already taken")

Both produce the same error structure on the client.

Default Error Shape (Formatted)

Mirrors the schema structure with _errors arrays at each level:

// For schema: z.object({ email: z.string().email(), address: z.object({ city: z.string() }) })
{
  _errors: ["Form-level error"],                    // root errors
  email: { _errors: ["Invalid email address"] },    // field errors
  address: {
    _errors: ["Address section error"],
    city: { _errors: ["City is required"] },        // nested field errors
  },
}

returnValidationErrors

Throws a ActionServerValidationError that the framework catches and returns as result.validationErrors. It never returns — it always throws.

"use server";

import { z } from "zod";
import { returnValidationErrors } from "next-safe-action";
import { actionClient } from "@/lib/safe-action";

const registerSchema = z.object({
  email: z.string().email(),
  username: z.string().min(3),
});

export const register = actionClient
  .inputSchema(registerSchema)
  .action(async ({ parsedInput }) => {
    // Check business rules after schema validation passes
    const existingUser = await db.user.findByEmail(parsedInput.email);
    if (existingUser) {
      returnValidationErrors(registerSchema, {
        email: { _errors: ["This email is already registered"] },
      });
    }

    const existingUsername = await db.user.findByUsername(parsedInput.username);
    if (existingUsername) {
      returnValidationErrors(registerSchema, {
        username: { _errors: ["This username is taken"] },
      });
    }

    // Both checks passed — create the user
    const user = await db.user.create(parsedInput);
    return { id: user.id };
  });

Root-Level Errors

Use _errors at the top level for form-wide errors:

returnValidationErrors(schema, {
  _errors: ["You can only create 5 posts per day"],
});

Supporting Docs

Displaying Validation Errors

// Formatted shape (default)
{result.validationErrors?.email?._errors?.map((error) => (
  <p key={error} className="text-red-500">{error}</p>
))}

// Root-level errors
{result.validationErrors?._errors?.map((error) => (
  <p key={error} className="text-red-500">{error}</p>
))}
// Flattened shape
{result.validationErrors?.fieldErrors?.email?.map((error) => (
  <p key={error} className="text-red-500">{error}</p>
))}

// Form-level errors (flattened)
{result.validationErrors?.formErrors?.map((error) => (
  <p key={error} className="text-red-500">{error}</p>
))}

Related skills

More from next-safe-action/skills and the wider catalog.

SA

safe-action-client

next-safe-action/skills

Use when creating or configuring a next-safe-action client, defining actions with input/output validation, handling server errors, or setting up createSafeActionClient with Standard Schema (Zod, Yup, Valibot)

913 installsAudited
SA

safe-action-forms

next-safe-action/skills

Use when integrating next-safe-action with forms -- react-hook-form adapter (useHookFormAction, useHookFormOptimisticAction, mapToHookFormErrors), native HTML forms, bind arguments, or file uploads

910 installsAudited
SA

safe-action-advanced

next-safe-action/skills

Use when working with bind arguments, metadata schemas, framework errors (redirect/notFound/forbidden/unauthorized), type inference utilities (InferSafeActionFnInput/Result), or server-level action callbacks

910 installsAudited
SA

safe-action-hooks

next-safe-action/skills

Use when executing next-safe-action actions from React client components -- useAction, useOptimisticAction, handling status/callbacks (onSuccess/onError/onSettled), execute vs executeAsync, or optimistic UI updates

903 installsAudited
SA

safe-action-middleware

next-safe-action/skills

Use when implementing middleware for next-safe-action -- authentication, authorization, logging, rate limiting, error interception, context extension, or creating standalone reusable middleware with createMiddleware() or createValidatedMiddleware(). Covers both use() (pre-validation) and useValidated() (post-validation) middleware.

893 installsAudited
SA

safe-action-testing

next-safe-action/skills

Use when writing tests for next-safe-action actions or hooks -- Vitest patterns for testing server actions directly, middleware behavior, hooks with React Testing Library, validation errors, and server errors

867 installsAudited