Skip to main content
HTML Validation

Bad value “X” for attribute “async” on element “script”.

About This HTML Issue

The HTML specification defines boolean attributes as attributes whose presence indicates a true state and whose absence indicates false. According to the WHATWG HTML standard, a boolean attribute may only have three valid representations:

  • The attribute name alone (e.g., async)
  • The attribute with an empty string value (e.g., async="")
  • The attribute with a value matching its own name, case-insensitively (e.g., async="async")

Any other value — such as async="true", async="1", async="yes", or async="false" — is invalid HTML and will trigger this validation error. This is a common misunderstanding because developers often assume boolean attributes work like boolean values in programming languages, where you’d assign true or false.

Why this matters

While most browsers are lenient and will treat any value of async as the true state (since the attribute is present regardless of its value), using invalid values creates several problems:

  • Standards compliance: Invalid HTML may cause issues with strict parsers, validators, or tools that process your markup.
  • Misleading intent: Writing async="false" does not disable async behavior — the attribute is still present, so the browser treats it as enabled. This can lead to confusing bugs where a script behaves asynchronously even though the developer intended otherwise.
  • Maintainability: Other developers reading the code may misinterpret async="false" as actually disabling async loading.

To disable async behavior, you must remove the attribute entirely rather than setting it to "false".

How async works

For classic scripts with a src attribute, the async attribute causes the script to be fetched in parallel with HTML parsing and executed as soon as it’s available, without waiting for the document to finish parsing.

For module scripts (type="module"), the async attribute causes the module and all its dependencies to be fetched in parallel and executed as soon as they are ready, rather than waiting until the document has been parsed (which is the default deferred behavior for modules).

Examples

❌ Invalid: arbitrary values on async

<!-- Bad: "true" is not a valid boolean attribute value -->

<script async="true" src="app.js"></script>

<!-- Bad: "1" is not a valid boolean attribute value -->

<script async="1" src="analytics.js"></script>

<!-- Bad: "yes" is not a valid boolean attribute value -->

<script async="yes" src="tracker.js"></script>

<!-- Bad and misleading: this does NOT disable async -->

<script async="false" src="app.js"></script>

✅ Valid: correct boolean attribute usage

<!-- Preferred: attribute name alone -->

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

<!-- Also valid: empty string value -->

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

<!-- Also valid: value matching attribute name -->

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

<!-- Correct way to disable async: remove the attribute -->

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

✅ Valid: async with module scripts

<script async type="module" src="app.mjs"></script>

<script async type="module">
  import { init } from './utils.mjs';
  init();
</script>

This same rule applies to all boolean attributes in HTML, including defer, disabled, checked, required, hidden, and others. When in doubt, use the attribute name on its own with no value — it’s the cleanest and most widely recognized form.

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.