{"id":"3d14091ed810a546","repo":"typeorm/typeorm","slug":"cannot-perform-update-query-because-update-values-3d1409","errorCode":null,"errorMessage":"Cannot perform update query because update values are not defined. Call \"qb.set(...)\" method to specify updated values.","messagePattern":"Cannot perform update query because update values are not defined\\. Call \"qb\\.set\\(\\.\\.\\.\\)\" method to specify updated values\\.","errorType":"exception","errorClass":"UpdateValuesMissingError","httpStatus":null,"severity":"error","filePath":"src/query-builder/UpdateQueryBuilder.ts","lineNumber":731,"sourceCode":"                        this.dataSource.driver.options.type === \"spanner\") &&\n                    value === null\n                ) {\n                    updateColumnAndValues.push(this.escape(key) + \" = NULL\")\n                } else {\n                    // we need to store array values in a special class to make sure parameter replacement will work correctly\n                    // if (value instanceof Array)\n                    //     value = new ArrayParameter(value);\n\n                    const paramName = this.createParameter(value)\n                    updateColumnAndValues.push(\n                        this.escape(key) + \" = \" + paramName,\n                    )\n                }\n            })\n        }\n\n        if (updateColumnAndValues.length <= 0) {\n            throw new UpdateValuesMissingError()\n        }\n\n        // get a table name and all column database names\n        const whereExpression = this.createWhereExpression()\n        const returningExpression = this.createReturningExpression(\"update\")\n\n        if (returningExpression === \"\") {\n            return `UPDATE ${this.getTableName(\n                this.getMainTableName(),\n            )} SET ${updateColumnAndValues.join(\", \")}${whereExpression}` // todo: how do we replace aliases in where to nothing?\n        }\n        if (this.dataSource.driver.options.type === \"mssql\") {\n            return `UPDATE ${this.getTableName(\n                this.getMainTableName(),\n            )} SET ${updateColumnAndValues.join(\n                \", \",\n            )} OUTPUT ${returningExpression}${whereExpression}`\n        }","sourceCodeStart":713,"sourceCodeEnd":749,"githubUrl":"https://github.com/typeorm/typeorm/blob/04ff4daedcf60fa4ffd0d5d33bbafaac1a9bbc96/src/query-builder/UpdateQueryBuilder.ts#L713-L749","documentation":"Thrown (as UpdateValuesMissingError) at the end of UpdateQueryBuilder.createUpdateExpression() when updateColumnAndValues is empty after processing the SET object. This happens when every key in the SET was filtered out: either all columns are marked isUpdate:false, or (with entity metadata) the normalized values set had no updatable columns left.","triggerScenarios":"Calling update().set({...}).execute() where every column in the set is @Column({ update: false }) (e.g. createdAt), so the loop skips them all and the final length check trips. Also possible when the set object is empty after stripping undefined values.","commonSituations":"Trying to update a create-only/immutable column; passing an object whose only keys are non-updatable columns; dynamically building a patch that ends up empty; migrating a column to update:false without updating callers.","solutions":["Ensure at least one column in your .set(...) is updatable (@Column({ update: true }) or default).","If a column must be immutable, update a different column or remove update:false.","Before executing, confirm Object.keys(setObject).length > 0 and that at least one maps to an updatable column.","For dynamic patches, short-circuit (no-op) when the resolved updatable-column set is empty."],"exampleFix":"// before — only non-updatable columns\n@Entity()\nclass Post { @Column({ update: false }) createdAt: Date; }\nawait repo.update({ id }, { createdAt: new Date() }); // -> UpdateValuesMissingError\n\n// after — include an updatable column, or skip the call\nconst patch = { title: 'new' };\nif (Object.keys(patch).length) await repo.update({ id }, patch);","handlingStrategy":"validation","validationCode":"const updatable = new Set(\n  repo.metadata.columns.filter((c) => c.isUpdate).map((c) => c.propertyPath),\n);\nconst hasUpdatable = Object.keys(patch).some((k) => updatable.has(k));\nif (!hasUpdatable) throw new Error('Patch contains no updatable columns');\nawait repo.update({ id }, patch);","typeGuard":"function hasUpdatableColumn(metadata: import('typeorm').EntityMetadata, patch: object): boolean {\n  const updatable = new Set(metadata.columns.filter((c) => c.isUpdate).map((c) => c.propertyPath));\n  return Object.keys(patch).some((k) => updatable.has(k));\n}","tryCatchPattern":null,"preventionTips":["Ensure at least one column in set() is updatable (update: true).","Short-circuit (no-op) when a dynamic patch resolves to no updatable columns.","Review @Column({ update: false }) annotations before relying on a column in updates."],"tags":["update-query","update-values-missing","non-updatable-column","validation"],"analyzedSha":"04ff4daedcf60fa4ffd0d5d33bbafaac1a9bbc96","analyzedAt":"2026-08-03T18:27:32.281Z","schemaVersion":2}