{"id":"f99ea3a75ea51a4a","repo":"knex/knex","slug":"can-t-extend-viewbuilder-with-existing-method","errorCode":null,"errorMessage":"Can't extend ViewBuilder with existing method ('${methodName}').","messagePattern":"Can't extend ViewBuilder with existing method \\('(.+?)'\\)\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"lib/schema/viewbuilder.js","lineNumber":84,"sourceCode":"        return this;\n      },\n      defaultTo: function (defaultValue) {\n        self._statements.push({\n          grouping: 'alterView',\n          method: 'defaultTo',\n          args: [column, defaultValue],\n        });\n        return this;\n      },\n    };\n  },\n};\n\nhelpers.addQueryContext(ViewBuilder);\n\nViewBuilder.extend = (methodName, fn) => {\n  if (Object.prototype.hasOwnProperty.call(ViewBuilder.prototype, methodName)) {\n    throw new Error(\n      `Can't extend ViewBuilder with existing method ('${methodName}').`\n    );\n  }\n\n  assign(ViewBuilder.prototype, { [methodName]: fn });\n};\n\nmodule.exports = ViewBuilder;\n","sourceCodeStart":66,"sourceCodeEnd":93,"githubUrl":"https://github.com/knex/knex/blob/e25d54bcb707714a17f5a5744eba5c4246bb4d1d/lib/schema/viewbuilder.js#L66-L93","documentation":"ViewBuilder.extend is the plugin/extension hook (lib/schema/viewbuilder.js:82). Before assigning a new method onto the prototype it checks Object.prototype.hasOwnProperty.call(ViewBuilder.prototype, methodName); if a method with that name already exists it throws \"Can't extend ViewBuilder with existing method\". This prevents plugins from silently shadowing built-in or previously-registered methods.","triggerScenarios":"Calling ViewBuilder.extend('checkOption', fn) or any name already on ViewBuilder.prototype; loading two plugins that register the same method name; registering a plugin twice (e.g. in tests with hot-reload).","commonSituations":"Plugin name collision with a built-in (checkOption, columns, as, setSchema); duplicate plugin registration in a monorepo where two packages extend knex; version mismatch where a plugin registers a method that a newer knex added natively.","solutions":["Pick a unique method name (namespace it, e.g. 'myPluginCheckOption').","Remove the duplicate plugin load / guard registration with a flag.","Downgrade/upgrade the plugin to a version compatible with your knex.","If you truly intend to replace, delete the prototype property first (not recommended)."],"exampleFix":"// before\nViewBuilder.extend('columns', myColumns);\n// after\nViewBuilder.extend('myPluginColumns', myColumns);","handlingStrategy":"validation","validationCode":"const methodName = 'myCheckOption';\nif (!Object.prototype.hasOwnProperty.call(ViewBuilder.prototype, methodName)) {\n  ViewBuilder.extend(methodName, fn);\n} else {\n  // already registered, skip or pick a new name\n}","typeGuard":"const isViewBuilderMethodFree = (name) =>\n  !Object.prototype.hasOwnProperty.call(ViewBuilder.prototype, name);","tryCatchPattern":"try { ViewBuilder.extend('myMethod', fn); }\ncatch (e) {\n  if (/Can't extend ViewBuilder with existing method/.test(e.message)) {\n    // plugin already registered; ignore or use alternate name\n  } else throw e;\n}","preventionTips":["Namespace plugin method names to avoid collisions","Register plugins once at app bootstrap","Guard against double-registration in hot-reload/tests"],"tags":["schema","views","plugin","extend","prototype"],"analyzedSha":"e25d54bcb707714a17f5a5744eba5c4246bb4d1d","analyzedAt":"2026-08-03T18:35:32.148Z","schemaVersion":2}