ErrLookup › Background articles › "NotImplementedError: Subclasses should override this method" / "must be implemented" — abstract method errors explained
"NotImplementedError: Subclasses should override this method" / "must be implemented" — abstract method errors explained
Errors like "NotImplementedError raised by abstract `execute`", "Implement this method in child class", "sort method must be implemented", or "Subclasses must implement the json method" all come from the same pattern: a library base class declares a method that only raises, and your code invoked that stub instead of a real override. This happens when you instantiate an abstract base class directly, write a subclass that forgets to implement a required method, use the wrong method name or signature so the base stub stays in the lookup path, or call an optional capability a concrete class never implemented. This page explains how the pattern works across libraries and the general ways to fix and prevent it.
Distilled from 98 documented records across 40 repositories.
Background
The abstract-method-not-implemented family covers errors raised deliberately by a base class to enforce a contract. Instead of a language feature like Java's abstract keyword or Python's abc, most libraries implement abstractness manually: a method on the base class does nothing but raise NotImplementedError (Ruby, Python), throw an Error (JavaScript), or raise a framework-specific exception (Rails' InvalidConfigException in Yii actions, Puppet's DevError, Blockbase-style throwing getters in Bootstrap's Config). From the caller's side this looks like a runtime crash far from the mistake: you call storage.get(), parser.parse(), backend.delete(), or anim._draw_frame() and the base stub answers instead of a concrete implementation. The message text is often the closest thing to documentation the base class offers — Capistrano says 'Your SCM strategy module should provide a #check method', Pundit says 'You must define #resolve', fluentd says 'Implement this method in child class'.
The failure usually surfaces at first use, not at definition or construction time. fluentd's parser and storage plugins raise on the first parse or get call; Yii actions throw only when the route is first requested; Livewire synths can dehydrate successfully and only crash on the next request's hydration; Capistrano strategies fail mid-deploy — sometimes only on the second deploy, when #update runs against an existing cache clone that #test reported as present. A few libraries check earlier: Bootstrap's Config throws the moment a subclass without a static NAME getter is constructed, and matplotlib/JAX-style cases can be asserted in __init__. This timing gap is why the errors feel mysterious: the wrong code was written (or not written) long before anything failed.
Three sub-patterns appear across the records. First, the mandatory abstract method: every concrete subclass must override it (Loss.gradient, Fluent::Plugin::Parser#parse, GitHub::Markup::Implementation#render, SandboxBackendProtocol.id). Second, the pair-based contract: the base marks one method abstract but a related method must also be overridden for things to work — Livewire synths need both dehydrate and hydrate plus matchByType/hydrateFromType together, FPM packages need input to match output, Capistrano strategies need all six methods, CarrierWave cache storages need the full four-method cache interface. Third, the optional capability: the base stub exists because not every implementation supports the operation (deepagents backends' delete, fluentd's parse_io and parse_partial_data), and the library normally guards calls with a capability check like implement? or supports_delete — the error fires only when that guard is bypassed or the wrong type is chosen.
How strict the contract is varies by library. Some enforce it softly: deepagents documents that optional methods raise by design and callers should check supports_delete first; fluentd's implement? introspection makes optional APIs genuinely optional. Others have no introspection safety net at all, and the only defense is a test that calls the method. Message style also varies: some messages name the exact method to implement ('trailing? is not implemented for Prism::Comment'), some name the class ('LiteralVar subclasses must implement the json method'), and some point to a migration path (Puppet recommends porting to the Resource API). Note also that a few base classes are inconsistent internally — ML-From-Scratch's Loss.loss returns NotImplementedError instead of raising it, a latent bug — so behavior around this family is library-specific rather than universal.
Common causes
- Subclass forgot the override. A custom subclass implements part of the contract but omits the abstract method — a synth with match() but no hydrate(), a Loss with loss() but not gradient(), a strategy module with clone but not update. The base stub raises at first use, often well after the class was written.
- Abstract base class instantiated or called directly. The base class was never meant to be used: new Sort().sort(), Prism::Comment.new(...).trailing?, Fluent::Plugin::Storage used as a real storage, a bare OutgoingMessage written to. The stub exists precisely so this fails loudly instead of silently doing nothing.
- Wrong method name, arity, or signature. The developer implemented the concept under a different name or shape: render instead of input in SimpleForm, parse_line instead of parse in a fluentd parser, execute instead of run in a Yii action, or a method with mismatched arity so the base implementation remains in the lookup path. The override never actually replaces the stub.
- Paired contract only half-implemented. Many libraries require a group of methods together: Livewire's matchByType requires hydrateFromType, dehydrate requires hydrate; FPM's output requires input; CarrierWave cache storages need cache!, retrieve_from_cache!, delete_dir!, and clean_cache!. Implementing only one side works until the code path reaches the other.
- Optional capability invoked without a guard. Some stubs mark capabilities not every implementation has, such as deepagents backends' delete or fluentd parsers' parse_io and parse_partial_data. Calling them directly — bypassing implement?/supports_delete-style checks — or routing work to a backend lacking the capability raises the stub.
- Wrong class chosen for the job. A store-only engine configured as CarrierWave cache storage, an output-only FPM type used as -s source, or a generic code path that dispatches to an incomplete subclass. The error signals a capability gap in the selected class rather than a bug in your data.
- Refactor or version drift silently dropped the override. A rename removed sort() from a subclass, a method was aliased/delegated instead of defined so introspection and dispatch break, or a third-party plugin written against an older contract meets a newer base class (e.g. pre-3.5 Capistrano SCM gems).
What usually fixes it
- [object Object]
- [object Object]
- [object Object]
- [object Object]
- [object Object]
Documented occurrences
- sort method must be implemented (trekhleb/javascript-algorithms)
- NotImplementedError raised by abstract `execute` (backend does not implement `execute`) (langchain-ai/deepagents)
- NotImplementedError() (eriklindernoren/ML-From-Scratch)
- input should be implemented by classes inheriting from CollectionInput (heartcombo/simple_form)
- Connection#createClient not implemented by driver (Automattic/mongoose)
- You must define a "hydrateFromType" method (livewire/livewire)
- Your SCM strategy module should provide a #test method (capistrano/capistrano)
- trailing? is not implemented for #{self.class} (ruby/ruby)
- Optional API #parse_io is not implemented (fluent/fluentd)
- #{self.class.name} does not yet support reading #{self.type} packages (jordansissel/fpm)
- Implement this method in child class (fluent/fluentd)
- You have to implement the static method "NAME", for each component! (twbs/bootstrap)
- ErrorCode.SelectionError: You must override this method (toeverything/AFFiNE)
- ERR_METHOD_NOT_IMPLEMENTED: The _implicitHeader() method is not implemented (denoland/deno)
- Implement this method in child class (fluent/fluentd)
- get_class($this) . ' must define a "run()" method.' (yiisoft/yii2)
- Need to implement #cache! if you want to use #{self.class.name} as a cache storage. (carrierwaveuploader/carrierwave)
- NotImplementedError raised by abstract `delete` (backend does not implement `delete`) (langchain-ai/deepagents)
- To support listing resources of this type the '%{provider}' provider needs to implement an 'instances' class method returning the current set of resources. We recommend porting your module to the simpler Resource API instead: https://puppet.com/search/docs?keys=resource+api (puppetlabs/puppet)
- You must define a "dehydrate" method (livewire/livewire)
…and 78 more across the corpus — use search.
Honest provenance: generated on 2026-09-03 from AI-assisted analysis of the linked records. See how records are made.