What’s actually slowing this PC down?

Pick the symptom - the matching free tool is one click away.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Some links on this page are affiliate links: if you buy through them we may earn a commission, at no extra cost to you.

Short answer: this error means the browser could not find a usable audio or video source when play() was called. It does not automatically mean that the codec is unsupported. A wrong relative path, 404 response, HTML page returned instead of an MP3, invalid file, incorrect MIME type, cross-origin restriction, or autoplay policy can lead to the same failure.

Start by catching the play() Promise, checking the exact URL in DevTools, and confirming that the response is a real media file. For the common example new Audio("../../media/KR881.mp3").play(), the path and server response are the first things to investigate.

What the exception means

HTMLMediaElement.play() is asynchronous and returns a Promise. The Promise rejects when playback cannot begin. A source-related failure commonly appears as:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
NotSupportedError: Failed to load because no supported source was found

The browser may have found no usable source because the URL was unreachable, the response was invalid, or the media could not be decoded. Chromium separates this failure from autoplay-policy failures in its media implementation. See the Chromium media-element source.

Always handle the Promise:

const audio = new Audio("/media/KR881.mp3");

audio.play()
  .then(() => console.log("Playback started"))
  .catch(error => console.error(error.name, error.message));

NotAllowedError means the browser blocked playback under its autoplay policy, usually because there was no recent user interaction. That is different from NotSupportedError. AbortError generally indicates that playback was interrupted or superseded. See MDN’s play() documentation.

1. Check the URL before changing the codec

In this code:

const audio = new Audio("../../media/KR881.mp3");
audio.play();

the relative URL is resolved against the document’s base URL, not necessarily against the directory containing the JavaScript file. If the page is served from /app/, for example, ../../media/KR881.mp3 may resolve somewhere entirely different from the source-tree path you had in mind.

Print the resolved URL:

const audio = new Audio("../../media/KR881.mp3");
console.log(audio.src);

Then copy that URL into a browser tab. It should return or download the actual audio file—not a 404 page, application shell, login page, JSON response, or other HTML document.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Common path problems include:

  • The file is not in the directory implied by the URL.
  • The filename or extension is misspelled.
  • Uppercase and lowercase letters differ. This often works on a case-insensitive development machine but fails on a case-sensitive production server.
  • A leading slash was misunderstood. /media/song.mp3 means the origin root, not the folder containing the project source.
  • A framework’s public/static directory or bundler import convention was not followed.
  • A route fallback returns index.html for an unknown media URL.

Document-relative, root-relative, and imported assets

If the directory layout is:

project/
├── index.html
└── media/
    └── KR881.mp3

and index.html is in the project root, this is appropriate:

const audio = new Audio("./media/KR881.mp3");

When the file is served from the site origin’s root, this may be appropriate:

const audio = new Audio("/media/KR881.mp3");

In bundler-based projects, the asset may need to be imported:

import songUrl from "./assets/KR881.mp3";

const audio = new Audio(songUrl);

These are patterns, not universal framework rules. The generated URL shown in the browser’s Network panel is the authority.

Free tools Windows power users keep installed

One-click scans. No signup required.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

2. Use the Network panel to find the real failure

  1. Open DevTools and select Network.
  2. Clear the request log.
  3. Click the playback button.
  4. Filter for media, mp3, wav, ogg, or the filename.
  5. Inspect the request URL, status, redirects, response headers, and response size.
  6. Open the request URL directly or download the response to verify its contents.
  7. Check the Console for CORS, mixed-content, MIME, or authentication errors.
Network result Likely cause
404 Wrong path, filename, case, or static-asset configuration.
403 Permission, authentication, or server policy.
200 with text/html An error page, login page, or single-page-app fallback was returned instead of audio.
200 with an empty or implausibly small body Broken deployment or an empty asset.
CORS error The cross-origin server did not provide a suitable Access-Control-Allow-Origin header.
Mixed-content error An HTTPS page attempted to load media over HTTP.
No request appears The handler did not run, the URL was never assigned, or another JavaScript error stopped execution.

A 200 status alone does not prove that the media is valid. Servers frequently return an HTML fallback with status 200.

3. Run the project through a local web server

Opening an HTML file by double-clicking it gives the page a file:// URL. Simple local audio playback can work in some browsers and setups, but filesystem behavior, relative paths, modules, CORS, and security restrictions are less predictable than normal HTTP serving.

From the directory you want to expose, run:

python -m http.server 8000

Then visit http://localhost:8000/. The command serves the directory in which it was started, so run it from the directory containing your HTML file and media folder.

A local server does not repair a missing file, corrupt encoding, incorrect MIME type, or unsupported codec. It simply gives you predictable URL resolution and useful Network-panel results.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

4. Verify the MIME type and the file itself

The server should send an appropriate Content-Type, such as:

  • audio/mpeg for MP3
  • audio/ogg for Ogg audio
  • audio/wav for WAV
  • audio/mp4 for supported MP4 audio
  • video/mp4 for MP4 video
  • video/webm for WebM video

For an MP3 source, use the conventional MIME type audio/mpeg:

<audio controls>
  <source src="/media/song.mp3" type="audio/mpeg">
</audio>

audio/mp3 is commonly seen, but audio/mpeg is the conventional type. The response header from the server matters more than the filename extension.

Also confirm that the file is genuine media. An MP3 filename may contain a WAV file, an HTML error page, JSON, a partial upload, an empty output from a conversion job, or a corrupt encoding. Download the exact response and test it in a desktop media player or media-information utility. If it cannot be decoded outside the browser, JavaScript is not the cause.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

5. Check format and codec support

A filename such as .mp3, .mp4, or .webm does not guarantee that the contents are valid or that a particular browser can decode them. A media resource has a container or format and an encoded audio or video codec.

canPlayType() provides an advisory browser hint:

const audio = document.createElement("audio");
console.log(audio.canPlayType("audio/mpeg"));
// Usually "probably", "maybe", or ""

An empty string means the browser does not think it can play that type. However, a nonempty result does not verify that the URL exists or that the file is undamaged. See MDN’s canPlayType() reference.

For alternatives, provide multiple correctly declared sources:

<audio id="player" controls>
  <source src="/media/song.mp3" type="audio/mpeg">
  <source src="/media/song.ogg" type="audio/ogg">
  Your browser does not support HTML audio.
</audio>

If every URL is wrong, every response is invalid, or every type declaration is misleading, the browser can still report that no supported source was found. More sources are not a substitute for testing each request.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

6. Call play() from a user action

For reliable interactive playback, call play() directly from a button’s click handler:

<button id="play-button" type="button">Play song</button>
const audio = new Audio("/media/KR881.mp3");
const button = document.querySelector("#play-button");

button.addEventListener("click", async () => {
  try {
    await audio.play();
    console.log("Playing");
  } catch (error) {
    console.error("Could not play audio:", error.name, error.message);
  }
});

An asynchronous operation before play() can lose the user-gesture context in some browsers:

button.addEventListener("click", async () => {
  await someLongOperation();
  await audio.play();
});

If the rejection is NotAllowedError, investigate autoplay and interaction policy. Do not diagnose it as an MP3 or path problem.

7. Retain the audio object

Keeping one Audio instance makes pause, restart, status events, and cleanup straightforward. Creating a new instance on every click can result in multiple simultaneous players and makes later control difficult, although it is not usually the direct cause of NotSupportedError.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
const audio = new Audio("/media/song.mp3");

playButton.addEventListener("click", () => {
  audio.play().catch(console.error);
});

pauseButton.addEventListener("click", () => {
  audio.pause();
});

8. Play a file selected by the user

A browser cannot safely use an arbitrary path guessed from the user’s filesystem. For an <input type="file">, create a temporary object URL:

<input id="file-input" type="file" accept="audio/*">
<audio id="player" controls></audio>
const input = document.querySelector("#file-input");
const player = document.querySelector("#player");
let objectUrl;

input.addEventListener("change", () => {
  const file = input.files[0];
  if (!file) return;

  if (objectUrl) URL.revokeObjectURL(objectUrl);

  objectUrl = URL.createObjectURL(file);
  player.src = objectUrl;

  player.play().catch(error => {
    console.error("Selected file could not be played:", error);
  });
});

URL.createObjectURL() creates a temporary blob: URL. It does not upload the file or reveal an arbitrary local path. Revoke the previous URL when replacing it.

Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

9. Diagnose media state and selected source

This version logs the source the browser selected and any available media error:

const audio = new Audio();

 audio.addEventListener("error", () => {
  const mediaError = audio.error;
  console.error("Media error", {
    code: mediaError?.code,
    message: mediaError?.message,
    networkState: audio.networkState,
    readyState: audio.readyState,
    src: audio.currentSrc || audio.src
  });
});

audio.addEventListener("loadedmetadata", () => {
  console.log("Metadata loaded", {
    duration: audio.duration,
    currentSrc: audio.currentSrc
  });
});

audio.src = "/media/KR881.mp3";

document.querySelector("#play-song").addEventListener("click", async () => {
  try {
    await audio.play();
  } catch (error) {
    console.error("play() rejected:", error);
  }
});

The audio.error property and MediaError code can narrow the diagnosis, but they usually cannot tell you whether the original mistake was a path, server, or deployment configuration. The Network response remains essential.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

10. Check deployment-specific problems

CORS

Cross-origin media must satisfy the browser and the remote server’s policy. If the server does not send a suitable Access-Control-Allow-Origin header, the request may be blocked. Setting audio.crossOrigin = "anonymous" is not a universal fix: it only works when the remote server is configured accordingly, and it cannot repair a 404, invalid file, or unsupported codec.

For simple playback, configure the media host correctly. If you use the media with Web Audio, canvas, or APIs that inspect its data, CORS requirements can be stricter.

HTTPS, redirects, and authentication

  • An HTTPS page cannot normally load media over insecure HTTP because of mixed-content blocking.
  • A redirect may lead to a login page or another origin with different permissions.
  • Signed URLs can expire before playback begins.
  • Protected media may require credentials or headers that a plain media element does not send as expected.

Inspect the final URL and response, not only the original URL typed into the code.

Range requests

For longer audio and video, a server or CDN should support byte-range requests. Missing range support is more commonly associated with seeking and streaming problems than this exact exception, but it is worth checking when short files work and larger deployed files do not.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

A complete robust example

<button id="play-song" type="button">Play song</button>
<button id="pause-song" type="button">Pause</button>
<p id="status" role="status">Ready</p>

<script>
  const audio = new Audio("./media/KR881.mp3");
  const playButton = document.querySelector("#play-song");
  const pauseButton = document.querySelector("#pause-song");
  const status = document.querySelector("#status");

  audio.addEventListener("loadedmetadata", () => {
    status.textContent = `Ready (${audio.duration.toFixed(1)} seconds)`;
  });

  audio.addEventListener("error", () => {
    const mediaError = audio.error;
    status.textContent = "The media could not be loaded.";
    console.error("Media error", {
      code: mediaError?.code,
      message: mediaError?.message,
      currentSrc: audio.currentSrc || audio.src,
      networkState: audio.networkState,
      readyState: audio.readyState
    });
  });

  playButton.addEventListener("click", async () => {
    try {
      await audio.play();
      status.textContent = "Playing";
    } catch (error) {
      status.textContent = `Playback failed: ${error.name}`;
      console.error(error);
    }
  });

  pauseButton.addEventListener("click", () => {
    audio.pause();
    status.textContent = "Paused";
  });
</script>

Final troubleshooting checklist

  • Catch the play() Promise and print error.name.
  • Check audio.currentSrc and resolve the URL from the document location.
  • Open the exact URL directly.
  • Use DevTools Network to check status, redirects, response size, and Content-Type.
  • Make sure a 200 response contains media rather than HTML, JSON, or an application shell.
  • Check filename case and framework static-asset conventions.
  • Verify the downloaded file in another media player.
  • Use canPlayType() only as a preliminary compatibility hint.
  • Try a known-good format or provide multiple correctly declared sources.
  • Use a local HTTP server instead of relying on file://.
  • Call play() from a user click and distinguish NotAllowedError from NotSupportedError.
  • For remote media, check CORS, HTTPS, authentication, redirects, and range support.

The central diagnosis is simple: “no supported source” means no usable resource was available to the media element at that moment. Find out whether the failure is in the URL, response, file, codec, browser policy, or deployment configuration before changing the JavaScript.

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.