Skip to main content
HTML Validation

Element “script” must not have attribute “defer” unless attribute “src” is also specified.

About This HTML Issue

The defer and async boolean attributes control how and when an external script is fetched and executed relative to HTML parsing. These attributes exist specifically to optimize the loading of external resources. An inline <script> block (one without a src attribute) doesn’t need to be “downloaded” — its content is already embedded in the HTML document. Because of this, the defer attribute has no meaningful effect on inline scripts, and the HTML specification explicitly forbids this combination.

According to the WHATWG HTML living standard, the defer attribute “must not be specified if the src attribute is not present.” Browsers will simply ignore the defer attribute on inline scripts, which means the script will execute synchronously as if defer were never added. This can mislead developers into thinking their inline script execution is being deferred when it isn’t, potentially causing subtle timing bugs that are difficult to diagnose.

The same rule applies to the async attribute — it also requires the presence of a src attribute to be valid.

How to fix it

You have two options depending on your situation:

  1. If the script should be deferred, move the inline code into an external .js file and reference it with the src attribute alongside defer.
  2. If the script must remain inline, remove the defer attribute entirely. If you need deferred execution for inline code, consider placing the <script> element at the end of the <body>, or use DOMContentLoaded to wait for the document to finish parsing.

Examples

❌ Invalid: defer on an inline script

<script defer>
  console.log("hello");
</script>

This triggers the validation error because defer is present without a corresponding src attribute.

✅ Fix option 1: Add a src attribute

Move the JavaScript into an external file (e.g., app.js) and reference it:

<script defer src="app.js"></script>

The browser will download app.js in parallel with HTML parsing and execute it only after the document is fully parsed.

✅ Fix option 2: Remove defer from the inline script

If the script must stay inline, simply remove the defer attribute:

<script>
  console.log("hello");
</script>

✅ Fix option 3: Use DOMContentLoaded for deferred inline execution

If you need your inline script to wait until the DOM is ready, wrap the code in a DOMContentLoaded event listener:

<script>
  document.addEventListener("DOMContentLoaded", function() {
    console.log("DOM is fully parsed");
  });
</script>

This achieves a similar effect to defer but is valid for inline scripts.

❌ Invalid: async on an inline script

The same rule applies to async:

<script async>
  document.title = "Updated";
</script>

✅ Fixed

<script async src="update-title.js"></script>

Or simply remove async if the script is inline:

<script>
  document.title = "Updated";
</script>

Find issues like this automatically

Rocket Validator scans thousands of pages in seconds, detecting HTML issues across your entire site.

Help us improve our guides

Was this guide helpful?

Ready to validate your sites?
Start your free trial today.