safe-action-validation-errors について
next-safe-action のバリデーションエラーを扱うためのリファレンススキルです。自動・手動エラーの形式と、クライアントコードでの表示方法を説明します。
主な機能
- 01Schema による自動バリデーションエラー
- 02returnValidationErrors() による手動エラー
- 03フォーマット済み・フラット化エラー形式
- 04フォーム全体・フィールド単位のエラー表示
活用シーン
- 01フォームでフィールドエラーを表示
- 02フォーム全体の検証失敗を報告
- 03サーバー側の検証ルールを処理
インストール
コマンドをコピーしてターミナルで実行します。
$
npx skills add https:/ / github.com/ next-safe-action/ skills --skill safe-action-validation-errorsインストール後、Claude Code で/safe-action-validation-errorsを入力して読み込まれたか確認します。
同梱ファイルcustom-errors.mderror-shapes.md
詳細
next-safe-action の検証エラー
検証エラーの 2 つの発生源
- スキーマ検証 — 入力が
.inputSchema()に一致しない場合に自動的に行われます - 手動検証 — サーバーコード内で
returnValidationErrors()を使います(例:「メールアドレスはすでに使用されています」)
どちらもクライアントでは同じエラー構造になります。
デフォルトのエラー形式(フォーマット済み)
各階層に _errors 配列がある、スキーマ構造を反映した形式です。
// 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
ActionServerValidationError をスローします。フレームワークはこれをキャッチし、result.validationErrors として返します。戻り値を返すことはありません。必ずスローします。
想定される検証以外のエラー(「在庫切れ」「見つかりません」など)には、兄弟ヘルパーの
returnServerError(payload)も同じように機能します(内部でスローし、戻り値を返しません)が、result.serverErrorに型付きペイロードを設定し、handleServerErrorを経由しません。safe-action-client スキルを参照してください。
"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 };
});
ルートレベルのエラー
フォーム全体に関するエラーには、最上位の _errors を使います。
returnValidationErrors(schema, {
_errors: ["You can only create 5 posts per day"],
});
関連ドキュメント
検証エラーの表示
// 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>
))}
コメント
Markdown 対応