Troubleshooting
My CRUD routes return 404
Almost always one of:
- You stacked a second
@Controller().@Crud()already applies@Controller(path). Adding another@Controller('users')underneath it breaks route registration. Put the path inside@Crud({ path: 'users' })and remove the extra decorator. - No
path(and you removed@Controller). Withoutpath, the controller mounts at the entity name (e.g./User). Setpath: 'users'. - The route is disabled. Routes you list with
{ enabled: false }(or the shorthandfalse) are not registered.
"Service is not defined…"
The controller must expose the service as a property literally named service:
export class UserController {
constructor(public service: UserService) {} // ← `public service`
}A custom endpoint clashes with /:id
Define custom static routes (e.g. @Get('active')) in the controller body — they are registered before the generated /:id route, so /users/active won't be captured as findOne('active'). The generated /bulk and /reorder routes are likewise ordered ahead of /:id.
?withDeleted=true (or onlyDeleted) returns 400
Fixed in the current version — these flags now coerce "true"/"1" to booleans. If you still see it, make sure you're on the latest release.
Filtering by a column returns 400 "Invalid filter field"
Only real entity columns and resolvable relation paths are accepted in where. Check the spelling, and for relation columns include the relation: relations=["profile"]&where={"profile.age":{"$gte":18}}.
A big filter returns 414 (or the request is rejected)
A long query (a $in with many IDs, a large saved filter) can exceed the URL limit that proxies/CDNs enforce (~8 KB → 414 Request-URI Too Large). Keep reads as GET for the common case, and send the rare large query in a POST body handled as a GET — see Large queries.
Postgres array operators error on SQLite/MySQL
$contArr and $intersectsArr are PostgreSQL-only and return 400 elsewhere.
An aggregate or having returns 400
- The aggregate
fieldmust be a relation path (posts.id), not a plain column. - The
asalias must match^[A-Za-z_][A-Za-z0-9_]*$and not collide with a real column. - A
havingkey must reference an alias you defined inaggregatesfor the same request. See Querying → Aggregates.
A column I expected is missing / a field returns 400 "unknown field"
It may be hidden. Fields marked with @CrudHidden() or listed in @Crud({ hiddenFields }) are stripped from responses and rejected in where / order / aggregates / relations — by design, with the same error as an unknown field. Check your entity for @CrudHidden() and the controller for hiddenFields.
My Flutter/JS client sends a query the server rejects
The client builders (@ackplus/nest-crud-request, nest_crud_request) emit the exact wire format the server parses — keep the client version in step with the server. Both clients are pinned to the server's operator set by drift-guard tests, so a mismatch usually means a version skew. See Packages & links.
Peer dependency warnings on install
The package peer-depends on NestJS 10/11, TypeORM 0.3, class-validator, class-transformer, and @nestjs/swagger. Install versions that match your app.
Soft-delete routes don't exist
/:id/restore, /:id/trash, /restore/bulk, /trash/bulk are only generated when you pass softDelete: true to @Crud().