{"id":"27559999185673fa","repo":"knex/knex","slug":"can-t-extend-columnbuilder-with-existing-method","errorCode":null,"errorMessage":"Can't extend ColumnBuilder with existing method ('${methodName}').","messagePattern":"Can't extend ColumnBuilder with existing method \\('(.+?)'\\)\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"lib/schema/columnbuilder.js","lineNumber":95,"sourceCode":"  };\n\n['index', 'primary', 'unique'].forEach(function (method) {\n  ColumnBuilder.prototype[method] = function () {\n    if (this._type.toLowerCase().indexOf('increments') === -1) {\n      this._tableBuilder[method].apply(\n        this._tableBuilder,\n        [this._args[0]].concat(toArray(arguments))\n      );\n    }\n    return this;\n  };\n});\n\nColumnBuilder.extend = (methodName, fn) => {\n  if (\n    Object.prototype.hasOwnProperty.call(ColumnBuilder.prototype, methodName)\n  ) {\n    throw new Error(\n      `Can't extend ColumnBuilder with existing method ('${methodName}').`\n    );\n  }\n\n  assign(ColumnBuilder.prototype, { [methodName]: fn });\n};\n\nconst AlterMethods = {};\n\n// Specify that the column is to be dropped. This takes precedence\n// over all other rules for the column.\nAlterMethods.drop = function () {\n  this._single.drop = true;\n\n  return this;\n};\n\n// Specify the \"type\" that we're looking to set the","sourceCodeStart":77,"sourceCodeEnd":113,"githubUrl":"https://github.com/knex/knex/blob/e25d54bcb707714a17f5a5744eba5c4246bb4d1d/lib/schema/columnbuilder.js#L77-L113","documentation":"ColumnBuilder.extend (lib/schema/columnbuilder.js:91) lets plugins add chainable methods to column definitions inside createTable/alter callbacks. It refuses to overwrite an existing own property on ColumnBuilder.prototype, so any built-in chainable (e.g. notNullable, defaultTo, references, unsigned, index, etc.) or a previously-registered extension cannot be silently replaced.","triggerScenarios":"Calling ColumnBuilder.extend('notNullable', fn); loading two column-builder plugins that register the same method; an HMR/test setup that re-installs the same plugin twice on the same prototype.","commonSituations":"Plugin authors choosing common names like 'default', 'nullable', 'unique'; knex adding a new native chainable method that a plugin had already claimed under the same name in an older version.","solutions":["Namespace your method name (extend('myPluginDefault', fn)).","Guard registration to be idempotent: if (!Object.prototype.hasOwnProperty.call(ColumnBuilder.prototype, name)) ColumnBuilder.extend(name, fn).","Resolve the collision between the two plugins by renaming one.","Inspect existing prototype methods before picking a name."],"exampleFix":"// before\nColumnBuilder.extend('defaultTo', fn);\n\n// after\nColumnBuilder.extend('auditDefault', fn);","handlingStrategy":"validation","validationCode":"const { ColumnBuilder } = require('knex/lib/schema/columnbuilder');\nfunction safeExtend(name, fn) {\n  if (Object.prototype.hasOwnProperty.call(ColumnBuilder.prototype, name)) {\n    throw new Error(`Refusing to clobber ColumnBuilder method: ${name}`);\n  }\n  ColumnBuilder.extend(name, fn);\n}","typeGuard":"function isColumnExtendable(ColumnBuilder, name) {\n  return !Object.prototype.hasOwnProperty.call(ColumnBuilder.prototype, name);\n}","tryCatchPattern":"try {\n  ColumnBuilder.extend(name, fn);\n} catch (err) {\n  if (/Can't extend ColumnBuilder/.test(err.message)) return;\n  throw err;\n}","preventionTips":["Namespace column-builder extension names.","Guard registration with hasOwnProperty to stay idempotent.","Avoid names that read like built-in chainables (defaultTo, notNullable, references).","Re-run plugin loaders safely under HMR by checking existence first."],"tags":["schema","column","plugin","extend","api-misuse"],"analyzedSha":"e25d54bcb707714a17f5a5744eba5c4246bb4d1d","analyzedAt":"2026-08-03T18:35:32.148Z","schemaVersion":2}