When a Selenium command carries an element reference, what does the remote end check before answering stale element reference?
answer
- The driver resolves the id first
- Two conditions, either one is fatal
- One clause is about the document
- Active document versus the node's document
- The other clause is about attachment
basics
~20 sThe driver looks the opaque id up in its per-browsing-context element cache, then checks two things about the node: that its document is still the active one, and that the node is still attached to that document.
solid answer
~40 sEvery element command carries the opaque id, and the remote end must first turn it back into a node - the specification's *get a known element* step. An id it never issued for this browsing context yields `no such element`. An id it did issue is then tested against two staleness clauses: the node's document must still be the browsing context's **active document**, and the node must still be **connected** to that document's tree. Either failure produces `stale element reference`, surfaced in Java as `StaleElementReferenceException`. Crucially the driver stores a node, never the locator that found it, so it has nothing to re-run and deliberately refuses to guess - re-searching could hit a different row and approve the wrong timesheet.
code
java · 22 linesimport org.openqa.selenium.By;
import org.openqa.selenium.StaleElementReferenceException;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.chrome.ChromeDriver;
public class StaleApprovalRow {
public static void main(String[] args) {
ChromeDriver driver = new ChromeDriver();
try {
driver.get("https://payroll.internal/approvals");
WebElement row = driver.findElement(By.cssSelector("#pending-approvals tr[data-timesheet='4821']"));
driver.get("https://payroll.internal/approvals");
try {
row.getTagName();
} catch (StaleElementReferenceException e) {
System.out.println("the reference belonged to the previous document");
}
} finally {
driver.quit();
}
}
}go deeper
Recall that the driver holds a node behind the id, and that the command fails when that node is no longer part of the page it came from.
Explain the dereference step and both staleness clauses - node document no longer active, or node no longer connected - and why either one alone is enough.
Use the two clauses as a diagnosis: work out whether the document was replaced or the container re-rendered, and name the application behaviour that moved the node.
Own why the protocol refuses to self-heal here, and defend that failing loudly beats a silent re-match that could act on the wrong record.
## What a command carrying a handle does first Every command aimed at an element - clicking the approve button on a payroll timesheet, reading the row's total - carries the **opaque id** the remote end issued when the node was found. Before doing anything else, the remote end must turn that id back into a real DOM node. The W3C WebDriver specification calls this dereferencing step *get a known element*, and it is the single place both of the errors in this topic come from. The lookup runs against the **known elements** map: a cache the remote end keeps **per browsing context**, from id to node. Nothing about the locator that produced the id is stored. The remote end has no memory of `By.cssSelector("#pending-approvals button.approve")`; it kept a node, not a query, and it therefore has nothing it could re-run on your behalf. ## The two answers a dereference can fail with | Error | Means | Typical cause on the queue | |---|---|---| | `no such element` | the id is not in the known-elements map at all | an id from another browsing context, or one the test constructed | | `stale element reference` | the id is known, but the node behind it no longer qualifies | the approvals table re-rendered, or a new document loaded | The Java client surfaces these as `NoSuchElementException` and `StaleElementReferenceException`. They are genuinely different situations: the first says *I never issued this*, the second says *I issued this, and it no longer points at anything I may act on*. ## The staleness rule, in two clauses A known reference is **stale** when either of these holds: 1. The node's **node document is not the active document** of the browsing context. Loading a new payroll page into the tab replaces the document wholesale, so every id issued against the old one fails, including ids for elements the new page renders identically. 2. The node is **not connected** - it is no longer attached to the document tree of its own document. Replacing the approvals table's rows detaches the old row nodes; they still exist in memory while the id holds them, but they hang outside the tree. Either clause alone is enough. That is why a reference can go stale without any navigation at all, and why it can go stale even though the button is still visible on screen - the visible button is a **different node** that happens to render the same way. ## Same markup is not the same node This is the point most candidates miss. Suppose the payroll queue polls every fifteen seconds and re-renders the whole `#pending-approvals` table body. Timesheet 4821's approve button looks unchanged: same text, same classes, same position. It is nevertheless a **new DOM node**, and the remote end has either not seen it yet or has issued it a different id. The stored id still resolves to the old, detached node, so the next command fails. - Identical markup does not make identical identity; node identity is what the cache holds. - The failure is deterministic given the same re-render, not a race and not a timing artefact. - The error is raised by the remote end, not guessed at by the client library. - No timeout value changes the outcome: waiting longer on a dead reference cannot revive it, because nothing about the node will change back. ## Why the remote end refuses to be helpful It would be technically possible for a driver to notice the detachment and search again. The specification deliberately does not do this, and the reason is correctness rather than laziness. A re-search could match a different row - approving the wrong employee's timesheet - and the driver has no way to know which of several similar nodes the test meant. Failing loudly with `stale element reference` hands that decision back to the test author, who is the only party that knows whether "the approve button for timesheet 4821" and "the approve button in the second row" are the same intent. ## What to take into a diagnosis When this error appears on a payroll run, the useful question is not *what is flaky here* but *which of the two clauses fired*: 1. Did the document change under the test - a navigation, a form post, a full page replacement? Clause one. 2. Did the surrounding container re-render while the document stayed put - a poll, a filter, a row removed after approval? Clause two. 3. Was the id ever valid in this browsing context at all? Then the error would have been `no such element` instead, and the problem is elsewhere. Answering that tells you which part of the application moved the node, which is a far more precise starting point than treating the exception as generic instability.
- Which error comes back for an id the driver never issued in this browsing context?`no such element`, surfaced in Java as `NoSuchElementException`. The lookup fails before staleness is ever considered, because the id is not in the known-elements map at all. That is a different diagnosis from a stale reference: it usually means an id crossed a context boundary or was constructed rather than received.
- Can a reference go stale without any navigation happening?Yes, and it is the common case. The second clause only requires the node to stop being connected to its document tree, so a poll that re-renders the approvals table detaches every old row while the document stays exactly the same. The button on screen afterwards is a different node with a different id.
- Why does the driver not simply re-run the locator when it sees a detached node?It never stored the locator - the cache maps an id to a node, not to a query - and re-searching would be unsafe even if it could. A second match might be a different row, so the driver would risk approving another employee's timesheet. Failing loudly returns that judgment to the test author.
saying these in an interview costs you the question
- Says the driver re-runs the locator automatically
- Blames the element merely being invisible
- Confuses no such element with stale element reference
- Thinks identical markup means the same node
- Believes a longer timeout revives an old reference