balderdashy/sails · warning
Cannot change primary key via update blueprint; ignoring val
Error message
Cannot change primary key via update blueprint; ignoring value sent for `${Model.primaryKey}` What it means
In the update blueprint's parameter parsing (parse-blueprint-options.js), if the request params include a new value for the model's primary key that differs from the PK in the request's where criteria, Sails logs this warning and forcibly keeps the original PK. Changing a record's primary key via the update blueprint is not allowed — you must drop and re-create the record.
Source
Thrown at lib/hooks/blueprints/parse-blueprint-options.js:316
// Note that we do NOT set `fetch: true`, because if we do so, some versions
// of Waterline complain that `fetch` need not be included with .updateOne().
// (Now that we take advantage of .updateOne() in blueprints, this is a thing.)
queryOptions.meta = {};
// ┌─┐┌─┐┬─┐┌─┐┌─┐ ┬ ┬┌─┐┬ ┬ ┬┌─┐┌─┐
// ├─┘├─┤├┬┘└─┐├┤ └┐┌┘├─┤│ │ │├┤ └─┐
// ┴ ┴ ┴┴└─└─┘└─┘ └┘ ┴ ┴┴─┘└─┘└─┘└─┘
queryOptions.valuesToSet = (function getValuesToSet(){
// Use all of the request params as values for the new record, _except_ `id`.
var values = _.omit(req.allParams(), 'id');
// No matter what, don't allow changing the PK via the update blueprint
// (you should just drop and re-add the record if that's what you really want)
if (typeof values[Model.primaryKey] !== 'undefined' && values[Model.primaryKey] !== queryOptions.criteria.where[Model.primaryKey]) {
req._sails.log.warn('Cannot change primary key via update blueprint; ignoring value sent for `' + Model.primaryKey + '`');
}
// Make sure the primary key is unchanged
values[Model.primaryKey] = queryOptions.criteria.where[Model.primaryKey];
return values;
})();
break;
// ██████╗ ███████╗███████╗████████╗██████╗ ██████╗ ██╗ ██╗
// ██╔══██╗██╔════╝██╔════╝╚══██╔══╝██╔══██╗██╔═══██╗╚██╗ ██╔╝
// ██║ ██║█████╗ ███████╗ ██║ ██████╔╝██║ ██║ ╚████╔╝
// ██║ ██║██╔══╝ ╚════██║ ██║ ██╔══██╗██║ ██║ ╚██╔╝
// ██████╔╝███████╗███████║ ██║ ██║ ██║╚██████╔╝ ██║
// ╚═════╝ ╚══════╝╚══════╝ ╚═╝ ╚═╝ ╚═╝ ╚═════╝ ╚═╝
case 'destroy':View on GitHub (pinned to 7b76422cc2)
Solutions
- Remove the primary key field from the update payload; send only mutable attributes.
- Ensure the id in the URL/body matches the record you intend to update.
- If PK changes are truly required, drop and re-add the record (custom action or direct database operation).
Example fix
// before
await fetch('/api/users/7', {method:'PUT', body: JSON.stringify({id: 9, name: 'x'})});
// after
await fetch('/api/users/7', {method:'PUT', body: JSON.stringify({name: 'x'})}); Defensive patterns
Strategy: validation
Validate before calling
const params = req.allParams();
if (params.id !== undefined && req.param('id') !== undefined && String(params[Model.primaryKey]) !== String(req.options.values?.where?.[Model.primaryKey] ?? req.params[Model.primaryKey])) {
delete params[Model.primaryKey]; // strip PK before sending update
} Prevention
- Never include the primary key in update payloads; whitelist mutable attributes.
- Strip immutable fields server-side before delegating to the update blueprint.
- Treat PKs as immutable — drop-and-recreate when a PK change is genuinely needed.
When it happens
Trigger: PUT/PATCH to a blueprint update route with a body that includes a field named after the primary key (usually 'id') whose value differs from the record's actual id in queryOptions.criteria.where.
Common situations: Client forms send the whole record including the id field while the route embeds a different id, generic UI components that serialize all fields on update, or bulk-edit frontends that let users edit the id column.
AI-assisted analysis of balderdashy/sails@7b76422cc2 (2026-09-01).
Data as JSON: /api/errors/c8855ad17a6780c4.
Report an issue: GitHub.