Safe Action Validation Errors

next-safe-action/skills/skills/safe-action-validation-errors

作者 next-safe-actiona2605bd2e84321245cba8f5718c144a6e4a5fa47無授權條款收錄於 2026年10月9日更新於 2026年10月9日

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

AI 產生的概覽

說明 next-safe-action 的驗證錯誤結構與輔助函式,用來回傳並顯示欄位層級與表單層級的錯誤。

功能
說明 next-safe-action 如何透過 schema 驗證與手動檢查產生驗證錯誤,涵蓋帶有巢狀 _errors 陣列的預設格式化結構,以及包含 fieldErrors 與 formErrors 的扁平化結構。它展示 returnValidationErrors 如何拋出 ActionServerValidationError 並最終呈現為 result.validationErrors,包括根層級表單錯誤,並提供渲染欄位錯誤與表單錯誤的 React 範例。另有兩份輔助文件分別說明自訂錯誤結構,以及格式化與扁平化輸出。
適用情境
適用於處理 next-safe-action 驗證錯誤的情境,包括 returnValidationErrors、格式化或扁平化錯誤結構、自訂驗證錯誤結構,以及在表單中渲染欄位層級與表單層級的錯誤。
執行需求
不含指令碼,僅為說明文件。假定使用 next-safe-action 專案,並搭配 Zod 等 schema 函式庫,顯示範例需要 React 前端。

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:

ts
// 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.

For expected non-validation errors ("out of stock", "not found"), the sibling helper returnServerError(payload) works the same way (throws internally, never returns) but sets result.serverError to the typed payload, bypassing handleServerError. See the safe-action-client skill.

ts
"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:

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

Supporting Docs

  • Custom validation errors and returnValidationErrors patterns
  • Formatted vs flattened shapes, per-action override

Displaying Validation Errors

tsx
// 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>))}
tsx
// 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>))}

來源與署名

來源:next-safe-action/skills位於skills/safe-action-validation-errors提交a2605bd

授權條款: 無授權條款

內容歸原作者所有。SourceWeft 從公開儲存庫中收錄這些內容。

檢舉或申請下架