ErrLookupBackground 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

What usually fixes it

Documented occurrences

…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.