Skip to main content
business computer-science journalism-media-studies-and-communication law

Chain of responsibility

Description

A request travels along a chain of handlers, each of which decides whether to take the request or pass it to the next handler. The sender doesn’t know who will ultimately handle the request; the handlers know only their immediate successor. The chain naturally orders handlers from most-specific (front) to most-generic (back), with a default or graceful-degradation behavior at the end. The defining property is the handler-acceptance decision: each handler asks “is this mine?” and either claims the request or defers. Compared to plain multi-hop routing, where every hop is a routing decision but the destination is implied by routing metadata, chain-of-responsibility makes the handler’s willingness the routing criterion: the request finds its handler by trial-pass rather than by addressing. The shape generalizes far beyond OOP. Customer support escalation, DOM event bubbling, HTTP middleware (an even more general decorator-chain), exception handlers, bug-triage queues, the legal escalation through courts of higher jurisdiction, and the editorial review chain at a publication all share this structure.

Triggers

User-initiated: User describes wanting “try X first, then Y, then Z” or escalation semantics. Vocabulary cues: “escalate,” “fall through,” “bubble up,” “try in order,” “first match wins,” “if not handled, then.” Agent-initiated: Agent notices nested if/else dispatching where a sequence of conditions is checked and the first match wins, especially when the conditions evolve over time. Candidate inference: “lift these into handler objects on a chain; new conditions become new handlers without disturbing the existing chain.” Situation-shape signals: Tiered processing hierarchies. Specificity gradients (most-specific first, falling back to general). Sender that shouldn’t need to know which handler will respond. Plugins / extensions that contribute conditional handling.

Exclusions

  • Handler selection is cheap and deterministic — if you know which handler the request belongs to from a simple lookup, dispatching through a chain is wasted work; direct dispatch is clearer and faster.
  • Order doesn’t matter — chain-of-responsibility is intrinsically ordered. If handlers should fire in parallel or in arbitrary order, observer / pub-sub is the right primitive.
  • Fall-through silently loses requests — if the chain reaches its end with no handler accepting and the request is silently dropped, you have a hidden failure mode. Always either have an explicit default at the chain’s tail or loudly fail on no-handler.
  • The chain becomes a god-class — when every handler “might handle” every request, the chain becomes a giant series of speculative checks. Specialization criteria need to be clear and disjoint enough that each request’s traversal is short.

Structure

Internal structure of chain-of-responsibility: a table of its component slots and the concepts that fill them.

Relationships

Relationship neighborhood of chain-of-responsibility: a graph of the concepts it connects to and the concepts it is a part of.
  • multi-hop-routing — chain-of-responsibility is the handler-acceptance specialization of multi-hop-routing; both have the each-hop-knows-only-next property, but chain decides on handler willingness while multi-hop routes by destination metadata.
  • graceful-degradation — chain-of-responsibility is one of the canonical mechanisms for graceful degradation: specific handlers at the front; broader fallbacks deeper; ultimate default at the end.
  • cost-cascade — cost-cascade is naturally a chain: cheap handler first; expensive handler downstream; the chain’s deferral semantics give the cascade its shape.
  • decorator — middleware chains are simultaneously decorator (each layer adds behavior) and chain-of-responsibility (each layer can short-circuit); the same primitive viewed from different intent lenses.
  • doctrine — escalation doctrines (tier 1 handles X; tier 2 handles Y; otherwise escalate) are chain-of-responsibility encoded in the doctrine’s named rules.

Examples

Web-framework middleware stacks (Ruby Rack; Node.js Express's `req, res, next` pipeline) — commonly characterized as a Chain of Responsibility blended with the Decorator pattern. · computer-science

The middleware pipelines at the heart of modern web frameworks — Ruby’s Rack, Node’s Express — are the most-encountered live instance of Chain of Responsibility. An incoming request enters a stack of middleware functions; each one may inspect or modify the request, handle it, and then pass control to the next handler (Express’s explicit next(); Rack’s call to the next app in the stack). The sender (the framework dispatching the request) does not know which handler will ultimately answer it, and each handler does not know what follows it — exactly the decoupling the pattern names. A middleware can also short-circuit the chain: an auth layer that returns 401 stops the request before it reaches the route handler, the classic Chain-of-Responsibility move of one handler accepting and terminating.It is usually described as a blend with the Decorator pattern, and the blend is structurally honest. Pure Chain of Responsibility passes a request along until exactly one handler consumes it and the traversal ends. Middleware departs from that in a telling way: most handlers do their work (logging, body-parsing, session setup) and then keep passing the request along, wrapping the eventual route handler in added behavior rather than competing to be the sole responder. So the chain provides the pass-and-short-circuit topology while the decorator provides the each-layer-adds-behavior semantics. Recognizing the chain part is what tells you the order of middleware is load-bearing and that any layer can quietly intercept the request before it reaches where you think it goes.

Customer-support tiered escalation · business

tier 1 attempts to resolve; escalates to tier 2; escalates to tier 3 / engineering.
bug goes to first reviewer; reviewer assigns or punts to next reviewer.
cross-domain reach into organizational/support contexts establishes chain-of-responsibility as a structural primitive about distributed handling, not a software trick
click events bubble from target node up through ancestors until a handler calls stopPropagation or the document is reached.
copy editor → managing editor → editor-in-chief; piece can be accepted, revised, or escalated at any level.
try/catch blocks form a chain up the call stack; each level decides handle or rethrow.
The Gang of Four catalogued Chain of Responsibility as one of the eleven behavioral patterns in the 1994 Design Patterns book. Their formal articulation: “Avoid coupling the sender of a request to its receiver by giving more than one object a chance to handle the request. Chain the receiving objects and pass the request along the chain until an object handles it.” The example they walked through is context-sensitive help in a UI framework, where a click on a button bubbles a help-request up through the button’s enclosing dialog and window, with each ancestor having an opportunity to claim and serve the request.The book’s contribution to the catalog is the naming and the generalization. Before GoF, the pattern existed implicitly in many systems (exception propagation in language runtimes, request-handler chains in Smalltalk UIs, escalation in customer-service organizations), but each domain had its own vocabulary. After GoF, the structural shape — ordered handlers, each deciding to handle or defer, sender unaware of which handler responds, handlers unaware of who comes after them in the chain — became a transferable design vocabulary. The decoupling is the load-bearing property: the chain can be reordered, extended, or shortened without the sender knowing. The pattern subsequently appears explicitly in HTTP middleware stacks (Rack, Express, ASP.NET, Servlet filters), DOM event-bubbling and event-capture, Python exception handlers, and Linux kernel-module dispatch.Once GoF named the move, cross-domain transfer became easier: an engineer noticing the shape in a new system could invoke the pattern and inherit the lessons from prior instances — handler ordering matters; loops are pathological; “no handler accepted” is a real terminal state that needs design.Inference: The GoF formulation makes the diagnostic question precise — is the next handler chosen by routing metadata on the request, or by each handler’s own decision to claim or defer? The first is a routing-table pattern; the second is chain-of-responsibility. The distinction matters because chain-of-responsibility composes naturally with graceful-degradation (specific handler at the front, broad fallback at the tail) while routing-table compositions degrade by producing 404-style errors when the addressed handler is absent.
request passes through middleware layers; any layer can short-circuit; reaches the route handler at the end.
handlers registered for signals; chain effectively forms by call patterns.