Message Passing on Graphs
Suppose you want to predict whether a molecule is toxic. You can only use its atoms and bonds. There is no grid to convolve, no sequence to scan. There is just a graph. The answer depends on how atoms are wired together into rings, branches, and functional groups. Standard Embeddings and Representation Learning techniques assign a vector to each atom. But a bare vector ignores structure entirely. It cannot tell a benzene ring from six disconnected carbons. Message passing is the computational primitive that fixes this. It lets every node's representation absorb information from its neighbors. This happens iteratively, until local structure becomes encoded in the vector itself. This idea is the computational core of nearly every modern graph neural network. Graphs are everywhere once you look: social networks, road networks, protein interaction networks, citation graphs, knowledge graphs, and the meshes used in physics simulation. Recommender systems at scale (user–item graphs), fraud detection (transaction graphs), drug discovery (molecular graphs), and traffic forecasting (sensor networks) all reduce to some flavor of "learn a function of a node's neighborhood, then repeat." The mechanism generalizes convolution — which aggregates fixed, regularly-spaced neighbors on a grid. Instead, it aggregates an arbitrary, variable-sized, unordered set of neighbors. It does this using a differentiable, permutation-invariant rule. The big picture: message passing treats a graph as a computational graph in its own right. Each round, every node sends a "message" to its neighbors. Every node aggregates the messages it receives. Every node updates its own state as a function of the aggregate and its previous state. Stack of these rounds, and a node's final representation depends on everything within distance in the graph. Its "receptive field" grows exactly as far as the graph lets it. This article gives the precise mechanics of one round of message passing. It covers what a message is. It also covers how aggregation must behave to respect the arbitrary ordering of neighbors. It also explains how updates compose across layers. It explains why this design is both expressive and tractable. It builds directly on the Attention Mechanism. Attention-weighted aggregation is one of the natural instantiations of "aggregate a variable-size neighborhood." It also sets up the fuller architectural picture given in Graph Neural Networks: An Introduction.
- Message passing generalizes convolution to irregular graphs: each node aggregates transformed features from its neighbors, then updates its own state.
- One round = message (per-edge function) → aggregate (permutation-invariant reduction) → update (combine aggregate with old state).
- Stacking rounds gives every node a receptive field of radius in the graph — the same intuition as stacking conv layers, but over an arbitrary topology.
- Aggregation must be permutation-invariant (sum, mean, max, or attention-weighted sum) because a node's neighbors have no canonical order.
- Time per layer is for hidden dimension ; space is for messages — linear in graph size.
- Over-smoothing (too many layers make all nodes look alike) and over-squashing (long-range signals bottlenecked through few edges) are the central failure modes to control.
Message passing turns a graph into an iterative computation where every node repeatedly aggregates transformed information from its neighbors and folds it into an updated, permutation-invariant representation of itself.
The idea
A graph has nodes , each carrying a feature vector (e.g., atom type, user profile, word embedding), and edges , optionally carrying their own features . Message passing is a computational scheme in which each node's representation is updated, layer by layer, as a function of its own previous representation and the representations of its neighbors . Formally, layer computes
Three roles matter here, and they generalize the "receptive field" language of convolutional networks:
- MESSAGE is a learned function applied per edge, typically an MLP or linear map on the concatenation (or difference) of the two endpoint features and the edge feature. It plays the role of a convolution's filter, but instead of a fixed spatial kernel it is applied identically to every edge regardless of how many neighbors a node has.
- AGGREGATE collapses a set of incoming messages — of variable, unknown size — into one fixed-size vector. Because a node's neighbors have no natural ordering (there is no "top" or "left" neighbor the way a pixel grid has), this function must be permutation-invariant: reordering the messages must not change the result. Sum, mean, max, and softmax-weighted sums (attention) all satisfy this; concatenation in a fixed order does not, unless neighbors are canonically sortable.
- UPDATE combines the aggregated neighborhood signal with the node's own previous state, typically via a gated combination (GRU-style), a residual/skip connection, or a simple concatenation followed by an MLP.
Stacking such layers is exactly analogous to stacking convolutional layers: after rounds, is a function of every node within graph-distance of — its -hop neighborhood. This is the graph analogue of a receptive field, except the "field" is not a fixed spatial patch but whatever the graph's actual connectivity happens to expose. When is instantiated as a softmax-weighted sum over neighbor messages — with weights computed from a compatibility score between and — message passing recovers graph attention, a direct graph-structured application of the Attention Mechanism; when it is instantiated as an unweighted sum with a learned linear message, it recovers the graph convolutional layer. Both are special cases of the same three-step primitive.
How it works
Concretely, running layers of message passing over an entire graph proceeds as follows. Note that all nodes update synchronously within a layer — layer 's messages always use layer 's representations, never a mixture of old and new, so the computation is well-defined and order-independent across nodes. ``` Input: graph G = (V, E) initial node features h[v] for v in V (h_v^(0)) optional edge features e[u, v] for (u, v) in E number of layers L learned functions MESSAGE_k, AGGREGATE_k, UPDATE_k for k = 1..L Output: node representations h[v] after L rounds (h_v^(L)) for k = 1 to L:
# --- Phase 1: compute messages on every edge, using LAST layer's states --- for each edge (u, v) in E: msg[u -> v] = MESSAGE_k(h[v], h[u], e[u, v])
# --- Phase 2: aggregate incoming messages per node --- for each node v in V: incoming = { msg[u -> v] : u in N(v) } agg[v] = AGGREGATE_k(incoming) # permutation-invariant reduction
# (if N(v) is empty, use a fixed default,
# e.g. agg[v] = 0, or h[v] itself)
# --- Phase 3: update every node's state, using OLD state + new aggregate --- for each node v in V: h_new[v] = UPDATE_k(h[v], agg[v]) h = h_new # commit synchronously: no node uses a partially-updated layer return h ``` Two implementation details matter for correctness. First, phases 2 and 3 must read `h` (the layer- values) throughout phase 1 and 2 — computing `agg[v]` must never see an already-updated `h[u]` from the same layer, or the result becomes order-dependent on how nodes happen to be iterated, breaking the guarantee that the whole layer is a well-defined function of the previous layer alone. Second, isolated nodes (empty neighborhoods) need an explicit default for `AGGREGATE`, since summation and mean are undefined (or division-by-zero) over the empty set; the standard convention is to treat the aggregate as the zero vector, or to add a self-loop so every node is its own neighbor. In vectorized form (as implemented in practice), the whole layer is a sparse matrix operation. Let stack all node states as rows, and let be the (possibly normalized) adjacency matrix. A basic graph-convolutional layer computes
where is the degree matrix of (adding self-loops so each node aggregates its own previous state too) and is a learned weight matrix shared across all nodes. Here is the aggregate-message step (a normalized sum over neighbors, done for all nodes simultaneously via one sparse matrix multiply), and followed by is the update/message transform. This is why message passing is efficient on real hardware: the "for each edge / for each node" loops in the pseudocode compile down to one sparse matrix–dense matrix multiplication per layer.
Complexity & correctness
Time complexity. For one layer, MESSAGE is computed once per directed edge; if MESSAGE is (e.g.) a linear map of concatenated -dimensional vectors followed by an activation, this costs per edge (dominated by the weight-matrix multiply), giving for the message phase — or if the message is a simple linear transform of a -vector reused across edges (as in , where the multiply is shared). AGGREGATE is a linear scan over each node's incoming messages, so summed across all nodes it touches each edge once: . UPDATE is applied once per node, typically another matrix multiply, giving . Total per layer:
and across layers, . This is linear in the size of the graph (nodes plus edges) for fixed hidden dimension and depth — the same complexity class as one pass of belief propagation or BFS with vector-valued payloads, and it is why message passing scales to graphs with millions of edges when implemented via sparse matrix multiplication on GPUs.
Space complexity. Storing all node states across layers costs (or if only the current layer is kept, at the cost of recomputing intermediates during backpropagation). Storing per-edge messages transiently costs . Total: , again linear in graph size.
Correctness argument — well-definedness and permutation invariance. The central thing to prove is not "the algorithm terminates" (it trivially does — fixed rounds over a fixed graph) but that the output is a well-defined function of the graph's isomorphism class and node features, independent of how nodes or neighbors happen to be indexed in memory. This matters because a graph has no canonical node ordering: two adjacency-matrix representations of the same graph, permuted by any , must yield permuted-but-identical outputs. Claim: if AGGREGATE is a permutation-invariant function of the multiset of incoming messages (sum, mean, max, or a softmax-weighted sum — anything that depends only on the multiset, not on an assumed order), then depends only on 's (isomorphism-invariant) rooted neighborhood structure up to depth , not on node indexing. Proof sketch by induction on . Base case : is v's own feature, trivially independent of any global ordering. Inductive step: assume for every node depends only on 's -hop rooted subgraph. Then is a multiset determined entirely by 's immediate neighbors and their -hop histories — not by any ordering imposed on by array indices. Applying a permutation-invariant AGGREGATE to this multiset yields a value depending only on the multiset, hence only on 's -hop rooted subgraph. UPDATE then combines two such invariant quantities, preserving invariance. This is precisely why concatenating neighbor features "in the order they appear in the adjacency list" is not a valid instantiation of AGGREGATE: it silently makes the model's output depend on an arbitrary index ordering, so isomorphic graphs (or the same graph with nodes relabeled) can get different outputs — a correctness bug, not just an inelegance.
Expressive power (and its limit). The above argument also exposes the ceiling on what sum/mean/max-aggregation message passing can distinguish: it is exactly as powerful as the 1-dimensional Weisfeiler-Leman graph isomorphism test. Any two nodes with identical multisets of -hop neighbor labels get identical — so if 1-WL cannot distinguish two graphs (there exist nontrivial non-isomorphic graphs it cannot, e.g. regular graphs with the same degree sequence), no sum/mean/max message-passing GNN can either, regardless of depth or width. This is a real, provable limitation, not a training artifact — it motivates strictly more expressive variants (higher-order WL, subgraph-based methods) covered separately.
Tradeoffs. Message passing buys locality-aware, permutation-invariant, linear-time computation on arbitrary topologies — but at real costs: (1) over-smoothing — as grows, repeated averaging drives all node representations in a connected component toward the same value, exactly as repeated application of a random-walk-like operator converges to a stationary distribution; (2) over-squashing — information from an exponentially large -hop neighborhood must be compressed into one fixed-size -dimensional vector, so long-range signal is bottlenecked and can be exponentially attenuated by the time it reaches a fixed-size receptive field passing through low-degree/bridge edges; (3) sum/mean/max aggregation is bounded by 1-WL expressiveness, so highly symmetric substructures may become indistinguishable no matter how deep the network goes.
Worked example
Consider a tiny 5-node graph — a molecule fragment abstraction — with node features being 1-D "atom weights" for simplicity (real GNNs use vectors, but a scalar trace makes the arithmetic checkable by hand): ``` Nodes: A(1.0) B(2.0) C(3.0) D(4.0) E(0.5) Edges: A-B, B-C, B-D, C-D, D-E ``` Adjacency (with self-loops added, -style, so every node aggregates itself too):
| node | neighbors incl. self |
|---|---|
| A | A, B |
| B | A, B, C, D |
| C | B, C, D |
| D | B, C, D, E |
| E | D, E |
Take MESSAGE (identity — pass the raw neighbor value), AGGREGATE = mean, UPDATE (replace with the aggregate; this is exactly one layer of unweighted, un-normalized "graph averaging," the simplest possible instantiation).
Layer 1 — average each node with its neighbors' initial values:
Layer 2 — average each node with its neighbors' layer-1 values (this is the crucial step: use for everyone, not a mix of and ):
Notice the spread: layer 0 values range over (spread 3.5); after layer 1, range is (spread 1.5); after layer 2, range is (spread 0.625) — this is over-smoothing in miniature: every additional round of neighborhood averaging on a small, well-connected graph pulls all values closer together, converging toward the graph's stationary "average" value as . A real GNN uses nonlinear MESSAGE and UPDATE functions with learned weights (so it need not converge this fast, and can in principle counteract smoothing via residual connections), but the qualitative mechanism — repeated local averaging homogenizes far-apart layers — is exactly this.
Common pitfalls & traps
| Pitfall | Why it breaks things |
|---|---|
| Using a non-permutation-invariant aggregator (e.g. concatenating neighbors in adjacency-list order) | Output silently depends on node indexing; isomorphic graphs get different predictions |
| Mixing layer- and layer- states within one round (updating nodes "in place" during aggregation) | Result depends on iteration order over nodes — breaks the well-definedness proof and gives nondeterministic-looking bugs |
| Forgetting self-loops or a skip connection in UPDATE | A node's own features get diluted or lost entirely, especially at high-degree nodes |
| Stacking too many layers naively | Over-smoothing — all node representations converge, hurting node-level classification accuracy |
| Ignoring edge features / treating all edges as identical | Loses relational information (bond type, edge weight, relation type in a knowledge graph) that MESSAGE could otherwise use |
| Assuming deeper always helps, like in CNNs | Depth also causes over-squashing on graphs with bottleneck edges — long-range signal from exponentially many source nodes is squeezed through a fixed-size vector |
| Not handling isolated nodes / empty neighborhoods | Mean/sum aggregation over an empty set is undefined or gives NaN without an explicit default |
Pioneers & history
Message passing as an explicit computational abstraction traces back to belief propagation on graphical models and to early neural approaches for structured data, before crystallizing into the modern "graph neural network" framing.
Origins · 1 minJudea Pearl and how this was discovered
Pearl formalized belief propagation — passing probabilistic messages along the edges of a graphical model to compute marginal beliefs — giving the algorithmic and mathematical template (local message exchange, iterative updates, convergence to a fixed point) that graph neural networks later adapted into a learned, differentiable form.
Scarselli and colleagues proposed the original Graph Neural Network, defining node states as the fixed point of a learned, contraction-mapping transition function over neighbors — an explicit precursor to today's fixed-depth message-passing layers, solved originally via iteration to convergence rather than a fixed number of stacked layers.
Where this matters
Message passing underlies production systems well beyond academic benchmarks. Pinterest's PinSAGE and related industrial recommenders run message passing over billion-node user–item graphs to generate embeddings for recommendation at web scale, using sampled neighborhoods to keep the linear-time-per-layer cost tractable. DeepMind's graph-network simulators use message passing over particle/mesh graphs to learn physics — fluid dynamics, cloth, rigid-body interactions — by treating each simulation step as one round of aggregate-and-update. Drug discovery pipelines (e.g., models behind antibiotic and antiviral candidate screening) represent molecules as atom-bond graphs and use message passing to predict properties like toxicity, solubility, and binding affinity, directly exploiting the permutation invariance argued above: a molecule's predicted property must not depend on the arbitrary order atoms are listed in a file. Traffic forecasting systems (e.g., Google Maps ETA prediction) run message passing over road-segment graphs so that congestion information propagates along actual road connectivity rather than geographic proximity. Fraud and anti-money-laundering systems propagate risk scores across transaction graphs using exactly this aggregate-and-update primitive, since a node (account) is suspicious partly because of who it transacts with. All of these are instances of the same three-step computational primitive introduced here, and they set up the fuller architectural taxonomy — GCN, GraphSAGE, GAT, and message-passing neural networks as a unifying framework — developed in Graph Neural Networks: An Introduction.
:::faq[What role does the Attention Mechanism play in message passing?] Attention supplies one natural, and now very popular, instantiation of AGGREGATE. Instead of averaging or summing neighbor messages with fixed or uniform weights, a Graph Attention Network computes a learned compatibility score between a node and each neighbor (using the same query-key scoring idea as sequence attention), converts the scores to weights via softmax over the neighborhood, and takes the weighted sum of neighbor messages as the aggregate. This preserves permutation invariance (softmax over a set, not a sequence, is still invariant to reordering) while letting the model learn that some neighbors matter more than others — e.g., a strong chemical bond should be weighted more than a weak one.
Ask the tutor: How does adding an attention mechanism to AGGREGATE change the expressiveness limits of message passing, and does it break or preserve the 1-WL equivalence?
Is message passing the same thing as a Graph Neural Network?
Not quite — message passing is the computational primitive, while a Graph Neural Network is the broader architecture built from it. A GNN specifies how many message-passing layers to stack, what MESSAGE/AGGREGATE/UPDATE functions to use (linear, attention-based, gated), how to read out a graph-level prediction from node states, and how to train the whole thing end-to-end. Concretely, GCN, GraphSAGE, and GAT are all "GNNs," and they differ from each other almost entirely in how they instantiate the message-passing primitive — different message functions, different aggregators, different neighbor-sampling strategies — while sharing the same underlying aggregate-then-update computational skeleton described here.
How is this different from convolution on images?
Convolution on an image aggregates a fixed, regularly-ordered set of neighbors (e.g., the 8 pixels in a 3×3 window), so the aggregation can simply be a weighted sum with position-specific weights — pixel "north" always gets the same filter weight. On a graph, nodes have variable numbers of neighbors with no canonical spatial ordering, so a position-specific weighting scheme cannot exist; message passing instead requires an aggregator that treats neighbors as an unordered multiset (sum, mean, max, or attention). You can view standard 2D convolution as a special case of message passing on the fixed grid graph, where every node happens to have exactly the same, orderable neighborhood shape.
Why do GNNs typically use only 2-4 message-passing layers, unlike CNNs which use dozens?
Two compounding effects limit useful depth on graphs. Over-smoothing means repeated neighborhood averaging drives node representations toward a shared, graph-wide average, erasing the local distinctions a task needs (as the worked example's shrinking spread demonstrates numerically). Over-squashing means that as the receptive field grows exponentially with depth, an exponentially large amount of information must still be compressed through the same fixed-size vector and through narrow "bottleneck" edges, causing gradient signal from distant nodes to vanish. CNNs avoid the first problem because pooling and strided convolutions deliberately downsample, and they mitigate the second with residual connections at very large scale; graph architectures need explicit countermeasures (residual/skip connections, gated updates, jumping-knowledge connections) to go much deeper than 2-4 layers.
Can message passing handle directed graphs and edge features?
Yes, straightforwardly, and both are common in practice. For directed graphs, MESSAGE is applied along the direction of each edge, and a node aggregates only over its (say) in-neighbors — or, if bidirectional influence is wanted, the architecture explicitly runs two passes, one over the graph and one over its reverse. Edge features (bond type, transaction amount, relation type in a knowledge graph) are simply concatenated into the MESSAGE function's input alongside the two endpoint states, letting the learned message depend on the nature of the connection, not just the connected nodes' values — this is essential in molecular and knowledge-graph applications where the type of edge often carries as much signal as the endpoints themselves.
Does message passing require the whole graph to fit in memory at once?
Not necessarily — this is precisely the problem neighbor-sampling methods (e.g., GraphSAGE-style sampling) solve for web-scale graphs. Because AGGREGATE only needs a node's immediate neighbors' previous-layer states, and stacking layers only needs the -hop neighborhood of the nodes being predicted, a mini-batch can be built by sampling a fixed-size subset of neighbors at each hop outward from a batch of target nodes, then running message passing only on that induced subgraph. This bounds memory and compute per batch independent of total graph size, at the cost of introducing sampling variance into the aggregate.