marmelab/react-admin · error
Invalid resource key: ${resource}
Error message
Invalid resource key: ${resource} What it means
The ra-data-local-storage provider throws this error to protect against prototype pollution. Resource keys in JavaScript objects are stored as object properties, so keys like '__proto__', 'constructor', or 'prototype' could overwrite Object.prototype and corrupt every object in the app. checkResource is called by the provider's data methods before any storage access to reject such keys.
Source
Thrown at packages/ra-data-local-storage/src/index.ts:172
return baseDataProvider.delete<RecordType>(resource, params);
},
deleteMany: (resource, params) => {
checkResource(resource);
updateLocalStorage(() => {
const indexes = params.ids.map(id =>
data[resource]?.findIndex(record => record.id == id)
);
pullAt(data[resource], indexes);
});
return baseDataProvider.deleteMany(resource, params);
},
};
};
const checkResource = resource => {
if (['__proto__', 'constructor', 'prototype'].includes(resource)) {
// protection against prototype pollution
throw new Error(`Invalid resource key: ${resource}`);
}
};
export interface LocalStorageDataProviderParams {
defaultData?: any;
localStorageKey?: string;
loggingEnabled?: boolean;
localStorageUpdateDelay?: number;
}
View on GitHub (pinned to 051f511bb0)
Solutions
- Audit where the resource argument comes from and stop passing '__proto__', 'constructor', or 'prototype' as resource names
- Validate resource names against your app's known resource list before calling the provider
- Sanitize dynamic resource identifiers extracted from URLs or user input with an allowlist
Example fix
// before
const resource = window.location.hash.slice(1);
dataProvider.getList(resource, params);
// after
const resource = window.location.hash.slice(1);
const allowed = ['posts', 'comments', 'users'];
if (!allowed.includes(resource)) throw new Error(`Unknown resource: ${resource}`);
dataProvider.getList(resource, params); Defensive patterns
Strategy: validation
Validate before calling
const FORBIDDEN = ['__proto__', 'constructor', 'prototype'];
const assertSafeResource = resource => {
if (typeof resource !== 'string' || FORBIDDEN.includes(resource)) {
throw new Error(`Invalid resource key: ${resource}`);
}
};
assertSafeResource(resource);
dataProvider.getList(resource, params); Type guard
const isSafeResource = (r: unknown): r is string =>
typeof r === 'string' && !['__proto__', 'constructor', 'prototype'].includes(r); Try / catch
try {
await dataProvider.getList(resource, params);
} catch (e) {
if (e instanceof Error && e.message.startsWith('Invalid resource key')) {
console.error('Blocked unsafe resource key:', resource);
return;
}
throw e;
} Prevention
- Validate dynamic resource names against an allowlist before provider calls
- Never derive resource names directly from user/URL input without sanitization
- Add a unit test asserting provider calls with '__proto__' are rejected
- Keep resource names as static string constants where possible
When it happens
Trigger: Calling any provider method (getList, getOne, create, update, delete, etc.) with resource set to '__proto__', 'constructor', or 'prototype', e.g. dataProvider.getList('__proto__', ...) or a List resource name="__proto__" propagated into provider calls.
Common situations: Dynamic resource names derived from URL path segments or user input that reach the data provider unvalidated; accidentally passing a variable that is undefined-adjacent or a literal meta-property; security tests probing for prototype pollution in a localStorage-backed admin.
Related errors
- Invalid resource key: ${resource}
- useCreate mutation requires a resource
- useCreate mutation requires a non-empty data object
- useDelete mutation requires a resource
- useDelete mutation requires a non-empty id
AI-assisted analysis of marmelab/react-admin@051f511bb0 (2026-08-30).
Data as JSON: /api/errors/f56f7fa1ad45bf5c.
Report an issue: GitHub.