diff --git a/changes/changelog.d/86.bugfix b/changes/changelog.d/86.bugfix
new file mode 100644
index 0000000000000000000000000000000000000000..c02a1997c0aae58d0f26ccbc68fbdf69803c9bc0
--- /dev/null
+++ b/changes/changelog.d/86.bugfix
@@ -0,0 +1 @@
+skip to next track properly on 40X errors (#86)
diff --git a/front/src/components/audio/Track.vue b/front/src/components/audio/Track.vue
index d8dcaff9b393013be60b2cb7e0b82ac0b6329e31..e2b613095c1aeb21ca997a2af144ce327bef20b1 100644
--- a/front/src/components/audio/Track.vue
+++ b/front/src/components/audio/Track.vue
@@ -7,7 +7,11 @@
     @timeupdate="updateProgress"
     @ended="ended"
     preload>
-    <source v-for="src in srcs" :src="src.url" :type="src.type">
+    <source
+      @error="sourceErrored"
+      v-for="src in srcs"
+      src="src.url"
+      :type="src.type">
   </audio>
 </template>
 
@@ -25,6 +29,11 @@ export default {
     startTime: {type: Number, default: 0},
     autoplay: {type: Boolean, default: false}
   },
+  data () {
+    return {
+      sourceErrors: 0
+    }
+  },
   computed: {
     ...mapState({
       playing: state => state.player.playing,
@@ -65,6 +74,13 @@ export default {
     errored: function () {
       this.$store.dispatch('player/trackErrored')
     },
+    sourceErrored: function () {
+      this.sourceErrors += 1
+      if (this.sourceErrors >= this.srcs.length) {
+        // all sources failed
+        this.errored()
+      }
+    },
     updateDuration: function (e) {
       this.$store.commit('player/duration', this.$refs.audio.duration)
     },