strapi/strapi · error · ValidationError
Invalid key ${key}
Error message
Invalid key ${key} What it means
Thrown by the same throwInvalidKey helper as error 80, but without a nested path suffix. The plain 'Invalid key ${key}' message is emitted when the violating key is at the top level of the query (path equals key or is absent), so no location qualifier is appended. It represents the same RBAC/schema validation failure class: a visitor detected a disallowed field during filters/sort/populate/fields traversal.
Source
Thrown at packages/core/admin/server/src/services/permission/permissions-manager/validate.ts:39
contentTypes;
const {
ID_ATTRIBUTE,
DOC_ID_ATTRIBUTE,
CREATED_AT_ATTRIBUTE,
UPDATED_AT_ATTRIBUTE,
PUBLISHED_AT_ATTRIBUTE,
CREATED_BY_ATTRIBUTE,
UPDATED_BY_ATTRIBUTE,
} = constants;
const COMPONENT_FIELDS = ['__component'];
const STATIC_FIELDS = [ID_ATTRIBUTE, DOC_ID_ATTRIBUTE];
const throwInvalidKey = ({ key, path }: { key: string; path?: string | null }) => {
const msg = path && path !== key ? `Invalid key ${key} at ${path}` : `Invalid key ${key}`;
throw new ValidationError(msg);
};
export default ({ action, ability, model }: any) => {
const schema = strapi.getModel(model);
// Create request-scoped model cache to avoid redundant getModel() calls
const modelCache = createModelCache(strapi.getModel.bind(strapi));
const ctx = {
schema,
getModel: modelCache.getModel,
};
const createValidateQuery = (options = {} as any) => {
const { fields } = options;
// TODO: validate relations to admin users in all validators
const permittedFields = fields.shouldIncludeAll ? null : getQueryFields(fields.permitted);View on GitHub (pinned to 4a4101264d)
Solutions
- Remove the offending key named in the message from the query.
- Grant the user's role read access to that field via the admin RBAC settings.
- If the field is hidden or private, switch to an allowed field or unhide it in the content-type schema.
- Sanitize client-supplied query parameters against the content-type's writable/visible attribute list before forwarding.
Example fix
// before
strapi.documents('api::article.article').findMany({
fields: ['title', 'internalNotes'], // internalNotes not permitted
});
// after
strapi.documents('api::article.article').findMany({
fields: ['title'],
}); Defensive patterns
Strategy: validation
Validate before calling
const visible = strapi.contentTypes[uid] ? Object.entries(strapi.contentTypes[uid].attributes).filter(([,a])=>!a.hidden).map(([k])=>k) : []; const safeFields = (query.fields || []).filter((f) => visible.includes(f));
Prevention
- Validate requested fields against the content-type's visible attributes.
- Avoid requesting hidden or password fields.
- Run RBAC field-permission checks in your API gateway/middleware.
When it happens
Trigger: A top-level query key violates the permission visitors: a disallowed field name in fields:[...], a top-level filter on a non-permitted attribute, a hidden attribute, a password field, or a disallowed admin::user field. Distinguished from error 80 only by the absence of a distinct nested path.
Common situations: Calling content-manager endpoints with a fields array or populate object that references a field the current role cannot read. A plugin auto-injecting query params that breach RBAC. Migrating from CE to EE where field-level permissions tighten enforcement.
Related errors
- Invalid key ${key} at ${path}
- Super admin permissions can't be edited.
- role.notFound
- Non-custom tokens should not reference permissions
- Missing permissions attribute for custom token
AI-assisted analysis of strapi/strapi@4a4101264d (2026-08-12).
Data as JSON: /api/errors/41b9d616db20cf2f.
Report an issue: GitHub.