How to Resolve the "DOMException: Failed to execute 'querySelector' on Document" Error in JavaScript
When using document.querySelector() or element.querySelector(), you may encounter the Uncaught DOMException: Failed to execute 'querySelector' on 'Document': '#123' is not a valid selector. This error occurs when you try to select an element whose ID or class name begins with a digit, which is invalid according to the CSS selector specification.
This guide will explain why this error happens and teach you the correct ways to solve it, starting with the recommended best practice of fixing your HTML, followed by workarounds for situations where you cannot change the markup.
The Core Problem: Invalid CSS Identifiers
The querySelector() and querySelectorAll() methods parse their arguments using CSS selector syntax. According to the CSS specification, an identifier (which is what IDs and class names are treated as in a selector) cannot start with a digit unless it is escaped.
Therefore, a simple selector like #1box is not valid, and the browser's CSS parser throws an error.
For example, this HTML uses an ID that starts with a digit, which is not a valid CSS identifier.
<!-- Problematic HTML: ID starts with a digit -->
<div id="1box">Box 1</div>
This JavaScript will cause the error because #1box is not a valid selector string.
// ⛔️ Uncaught DOMException: Failed to execute 'querySelector' on 'Document': '#1box' is not a valid selector.
const first = document.querySelector('#1box');
Solution 1 (Recommended): Fix the ID or Class Name
The best and most robust solution is to adhere to web standards. You should change your IDs and class names to ensure they do not start with a digit. This will prevent issues not just in JavaScript, but also in your CSS files.
Example of code with problem:
<!-- Problem: The ID "1box" is not a valid CSS identifier. -->
<div id="1box">Box 1</div>
Solution: modify the HTML to use a valid identifier. A common practice is to move the number to the end.
<!-- ✅ Corrected HTML: The ID now starts with a letter. -->
<div id="box-1">Box 1</div>
Now, your JavaScript querySelector call will work as expected without any tricks.
// This now works perfectly.
const first = document.querySelector('#box-1');
console.log(first); // Output: <div id="box-1">Box 1</div>
This is the recommended best practice as it solves the root of the problem.
Workarounds (When You Can't Change the HTML)
Sometimes you are working with legacy code or third-party content where you cannot change the HTML. In these cases, you can use one of the following workarounds.
Workaround A: Use the Attribute Selector
Instead of using the ID selector (#), you can use an attribute selector. This syntax is not bound by the same identifier rules.
Solution: the selector [id='1box'] tells the browser to find an element that has an id attribute with the exact string value "1box".
// This works because the value in quotes is treated as a string, not an identifier.
const first = document.querySelector("[id='1box']");
console.log(first); // Output: <div id="1box">Box 1</div>
This is a reliable workaround when using querySelector.
Workaround B: Use document.getElementById()
The getElementById() method is not a CSS selector parser. It is a direct DOM method that takes a string and looks for an element with a matching id attribute. As such, it is not bound by the CSS identifier rules and will work correctly with IDs that start with a digit.
Solution:
// getElementById is not a CSS selector, so it works.
const first = document.getElementById('1box');
// Note: No '#' prefix is used with this method.
console.log(first); // Output: <div id="1box">Box 1</div>
This is often the cleanest and fastest workaround if you only need to select an element by its ID.
Conclusion: Which Method Should You Use?
The best solution depends on your ability to change the HTML.
- Best Practice: If you have control over the HTML, fix the ID or class name to not start with a digit. This is the most correct and future-proof solution.
- If You Can't Change the HTML:
- To select by ID only,
document.getElementById()is the cleanest and most direct workaround. - If you need to use
querySelector(for example, to use more complex selectors), use the attribute selector syntax ([id='1box']).
- To select by ID only,