jhy/jsoup · error · IndexOutOfBoundsException

No child at index:

Error message

No child at index: 

What it means

Element.child(int index) indexes only child nodes that are themselves Elements (skipping text/comment nodes). If the element has fewer element children than the requested index, jsoup throws IndexOutOfBoundsException with 'No child at index: N'.

Solutions

  1. Check element.childrenSize() (or children().size()) before calling child(index)
  2. Use children().get(index) with a bounds check, or select(...) with a CSS selector to target the element directly
  3. If you need raw child nodes including text, use childNode(index) / childNodes() instead
  4. Verify the parsed document actually contains the expected structure (log element.children() during debugging)

Example fix

// before
Element first = doc.body().child(0); // throws if body has only text
// after
Elements kids = doc.body().children();
Element first = kids.isEmpty() ? null : kids.get(0);
Defensive patterns

Strategy: validation

Validate before calling

Element safeChild(Element parent, int index) { return index >= 0 && index < parent.childrenSize() ? parent.child(index) : null; }

Try / catch

try { Element e = parent.child(i); } catch (IndexOutOfBoundsException e) { Element e = null; /* handle missing child */ }

Prevention

When it happens

Trigger: Calling element.child(i) where i >= element.childrenSize(); e.g. element.child(0) on an element containing only text nodes, or child(5) on a table whose 5th child is a text node.

Common situations: HTML where whitespace/text nodes interleave with elements and developers assume child indexes match childNodes() indexes; empty or unexpectedly structured documents after a site layout change.

Related errors


AI-assisted analysis of jhy/jsoup@9851ac5d9c (2026-09-08). Data as JSON: /api/errors/c9623253e02786c3. Report an issue: GitHub.

Appendix: source

Thrown at src/main/java/org/jsoup/nodes/Element.java:368

     * </p>
     *
     * @param index the index number of the element to retrieve
     * @return the child element, if it exists, otherwise throws an {@code IndexOutOfBoundsException}
     * @see #childNode(int)
     */
    public Element child(int index) {
        Validate.isTrue(index >= 0, "Index must be >= 0");
        List<Element> cached = cachedChildren();
        if (cached != null) return cached.get(index);
        // otherwise, iter on elementChild; saves creating list
        int size = childNodes.size();
        for (int i = 0, e = 0; i < size; i++) { // direct iter is faster than chasing firstElSib, nextElSibd
            Node node = childNodes.get(i);
            if (node instanceof Element) {
                if (e++ == index) return (Element) node;
            }
        }
        throw new IndexOutOfBoundsException("No child at index: " + index);
    }

    /**
     * Get the number of child nodes of this element that are elements.
     * <p>
     * This method works on the same filtered list like {@link #child(int)}. Use {@link #childNodes()} and {@link
     * #childNodeSize()} to get the unfiltered Nodes (e.g. includes TextNodes etc.)
     * </p>
     *
     * @return the number of child nodes that are elements
     * @see #children()
     * @see #child(int)
     */
    public int childrenSize() {
        if (childNodeSize() == 0) return 0;
        return childElementsList().size(); // gets children into cache; faster subsequent child(i) if unmodified
    }

View on GitHub (pinned to 9851ac5d9c)