Validation
When a request fails validation, Arkos automatically formats the error into a consistent response. The code field identifies which part of the request failed — body, query, or params. The message field contains the first validation error in human-readable form. The full list of errors is available in meta.
Response Shape
{
"status": "error",
"code": "InvalidRequestBody",
"message": "'email' must be a valid email address",
"meta": {
"errors": [
{
"message": "'email' must be a valid email address",
"code": "EmailIsEmailConstraint"
},
{
"message": "'name' must be at least 2 characters",
"code": "NameMinLengthConstraint"
}
]
}
}The code field will be one of:
| Code | Trigger |
|---|---|
InvalidRequestBody | req.body failed validation |
InvalidRequestQuery | req.query failed validation |
InvalidRequestParams | req.params failed validation |
Nested and Array Fields
Arkos includes the full field path in error messages so you always know exactly what failed:
{
"code": "InvalidRequestBody",
"message": "'user.profile.bio' must be at least 10 characters",
"meta": { "errors": [...] }
}{
"code": "InvalidRequestBody",
"message": "'tags[0].name' must be a string",
"meta": { "errors": [...] }
}Unknown Fields
By default Arkos passes blocks unknown fields. You can customize this behavior by using forbidNonWhitelisted in your validationOptions:
import { defineConfig } from "arkos/config";
export default defineConfig({
validation: {
resolver: "zod",
validationOptions: {
forbidNonWhitelisted: true,
},
},
});import { ArkosConfig } from "arkos";
const arkosConfig: ArkosConfig = {
validation: {
resolver: "zod",
validationOptions: {
forbidNonWhitelisted: true,
},
},
};
export default arkosConfig;import arkos from "arkos";
arkos.init({
validation: {
resolver: "class-validator",
validationOptions: {
forbidNonWhitelisted: true,
},
},
});When an unrecognized field is sent:
{
"status": "error",
"code": "InvalidRequestBody",
"message": "Unrecognized key(s) in object: 'isAdmin'",
"meta": { "errors": [...] }
}Enabling forbidNonWhitelisted is recommended. It prevents mass assignment vulnerabilities where unexpected fields slip through into your database operations.
Strict Mode
Strict mode requires every route to explicitly declare its validation intent at startup — no route can silently pass unvalidated input. See Validation — Setup for the full strict mode rules and behavior table.
Blocking Input Entirely
To prohibit a specific input type on a route entirely — for example, rejecting any query string — pass null to that key in validation:
router.get(
{
path: "/api/reports/:id",
validation: {
body: null, // not allowed — returns 400 if sent
},
},
reportController.getOne
);See Validation — Setup for the full behavior table.