diff --git a/src/playlist/Length.cxx b/src/playlist/Length.cxx
index 146e675fa..2aeecf144 100644
--- a/src/playlist/Length.cxx
+++ b/src/playlist/Length.cxx
@@ -10,6 +10,7 @@
 #include "SongPrint.hxx"
 #include "song/DetachedSong.hxx"
 #include "song/LightSong.hxx"
+#include "input/Error.hxx"
 #include "fs/Traits.hxx"
 #include "thread/Mutex.hxx"
 #include "Partition.hxx"
@@ -50,7 +51,7 @@ void
 playlist_file_length(Response &r, Partition &partition,
 		     const SongLoader &loader,
 		     const LocatedUri &uri)
-{
+try {
 	Mutex mutex;
 
 #ifndef ENABLE_DATABASE
@@ -66,4 +67,9 @@ playlist_file_length(Response &r, Partition &partition,
 		throw PlaylistError::NoSuchList();
 
 	playlist_provider_length(r, loader, uri.canonical_uri, *playlist);
+} catch (...) {
+	if (IsFileNotFound(std::current_exception()))
+		throw PlaylistError::NoSuchList();
+
+	throw;
 }
diff --git a/src/playlist/PlaylistAny.hxx b/src/playlist/PlaylistAny.hxx
index 9733e8eb7..9c24c5379 100644
--- a/src/playlist/PlaylistAny.hxx
+++ b/src/playlist/PlaylistAny.hxx
@@ -1,8 +1,7 @@
 // SPDX-License-Identifier: GPL-2.0-or-later
 // Copyright The Music Player Daemon Project
 
-#ifndef MPD_PLAYLIST_ANY_HXX
-#define MPD_PLAYLIST_ANY_HXX
+#pragma once
 
 #include "thread/Mutex.hxx"
 #include "config.h"
@@ -16,6 +15,10 @@ class Storage;
  * Opens a playlist from the specified URI, which can be either an
  * absolute remote URI (with a scheme) or a relative path to the
  * music or playlist directory.
+ *
+ * Throws on error.
+ *
+ * @return a playlist, or nullptr if the file is not supported
  */
 std::unique_ptr<SongEnumerator>
 playlist_open_any(const LocatedUri &located_uri,
@@ -23,5 +26,3 @@ playlist_open_any(const LocatedUri &located_uri,
 		  const Storage *storage,
 #endif
 		  Mutex &mutex);
-
-#endif
diff --git a/src/playlist/PlaylistMapper.hxx b/src/playlist/PlaylistMapper.hxx
index b3b20ee08..b3c78c0be 100644
--- a/src/playlist/PlaylistMapper.hxx
+++ b/src/playlist/PlaylistMapper.hxx
@@ -1,8 +1,7 @@
 // SPDX-License-Identifier: GPL-2.0-or-later
 // Copyright The Music Player Daemon Project
 
-#ifndef MPD_PLAYLIST_MAPPER_HXX
-#define MPD_PLAYLIST_MAPPER_HXX
+#pragma once
 
 #include "thread/Mutex.hxx"
 #include "config.h"
@@ -15,6 +14,10 @@ class Storage;
 /**
  * Opens a playlist from an URI relative to the playlist or music
  * directory.
+ *
+ * Throws on error.
+ *
+ * @return a playlist, or nullptr if the file is not supported
  */
 std::unique_ptr<SongEnumerator>
 playlist_mapper_open(const char *uri,
@@ -22,5 +25,3 @@ playlist_mapper_open(const char *uri,
 		     const Storage *storage,
 #endif
 		     Mutex &mutex);
-
-#endif
diff --git a/src/playlist/PlaylistQueue.cxx b/src/playlist/PlaylistQueue.cxx
index 1f382ce93..85b33af4c 100644
--- a/src/playlist/PlaylistQueue.cxx
+++ b/src/playlist/PlaylistQueue.cxx
@@ -10,6 +10,7 @@
 #include "queue/Playlist.hxx"
 #include "SongEnumerator.hxx"
 #include "song/DetachedSong.hxx"
+#include "input/Error.hxx"
 #include "thread/Mutex.hxx"
 #include "fs/Traits.hxx"
 #include "Log.hxx"
@@ -61,7 +62,7 @@ playlist_open_into_queue(const LocatedUri &uri,
 			 unsigned start_index, unsigned end_index,
 			 playlist &dest, PlayerControl &pc,
 			 const SongLoader &loader)
-{
+try {
 	Mutex mutex;
 
 	auto playlist = playlist_open_any(uri,
@@ -75,4 +76,9 @@ playlist_open_into_queue(const LocatedUri &uri,
 	playlist_load_into_queue(uri.canonical_uri, *playlist,
 				 start_index, end_index,
 				 dest, pc, loader);
+} catch (...) {
+	if (IsFileNotFound(std::current_exception()))
+		throw PlaylistError::NoSuchList();
+
+	throw;
 }
diff --git a/src/playlist/PlaylistQueue.hxx b/src/playlist/PlaylistQueue.hxx
index 7fe05d872..e81500166 100644
--- a/src/playlist/PlaylistQueue.hxx
+++ b/src/playlist/PlaylistQueue.hxx
@@ -1,13 +1,12 @@
 // SPDX-License-Identifier: GPL-2.0-or-later
 // Copyright The Music Player Daemon Project
 
+#pragma once
+
 /*! \file
  * \brief Glue between playlist plugin and the play queue
  */
 
-#ifndef MPD_PLAYLIST_QUEUE_HXX
-#define MPD_PLAYLIST_QUEUE_HXX
-
 class SongLoader;
 class SongEnumerator;
 struct playlist;
@@ -31,12 +30,11 @@ playlist_load_into_queue(const char *uri, SongEnumerator &e,
 /**
  * Opens a playlist with a playlist plugin and append to the specified
  * play queue.
+ *
+ * Throws on error.
  */
 void
 playlist_open_into_queue(const LocatedUri &uri,
 			 unsigned start_index, unsigned end_index,
 			 playlist &dest, PlayerControl &pc,
 			 const SongLoader &loader);
-
-#endif
-
diff --git a/src/playlist/PlaylistStream.cxx b/src/playlist/PlaylistStream.cxx
index 859f9f869..5db8b9a0a 100644
--- a/src/playlist/PlaylistStream.cxx
+++ b/src/playlist/PlaylistStream.cxx
@@ -8,14 +8,13 @@
 #include "input/LocalOpen.hxx"
 #include "fs/Path.hxx"
 #include "util/UriExtract.hxx"
-#include "Log.hxx"
 
 #include <cassert>
 #include <exception>
 
 static std::unique_ptr<SongEnumerator>
 playlist_open_path_suffix(Path path, Mutex &mutex)
-try {
+{
 	assert(!path.IsNull());
 
 	const auto *suffix = path.GetExtension();
@@ -29,14 +28,11 @@ try {
 	auto is = OpenLocalInputStream(path, mutex);
 	return playlist_list_open_stream_suffix(std::move(is),
 						suffix_utf8);
-} catch (...) {
-	LogError(std::current_exception());
-	return nullptr;
 }
 
 std::unique_ptr<SongEnumerator>
 playlist_open_path(Path path, Mutex &mutex)
-try {
+{
 	assert(!path.IsNull());
 
 	const std::string uri_utf8 = path.ToUTF8Throw();
@@ -45,14 +41,11 @@ try {
 		playlist = playlist_open_path_suffix(path, mutex);
 
 	return playlist;
-} catch (...) {
-	LogError(std::current_exception());
-	return nullptr;
 }
 
 std::unique_ptr<SongEnumerator>
 playlist_open_remote(const char *uri, Mutex &mutex)
-try {
+{
 	assert(uri_has_scheme(uri));
 
 	auto playlist = playlist_list_open_uri(uri, mutex);
@@ -61,7 +54,4 @@ try {
 
 	auto is = InputStream::OpenReady(uri, mutex);
 	return playlist_list_open_stream(std::move(is), uri);
-} catch (...) {
-	LogError(std::current_exception());
-	return nullptr;
 }
diff --git a/src/playlist/PlaylistStream.hxx b/src/playlist/PlaylistStream.hxx
index 9e2031410..4af296a9c 100644
--- a/src/playlist/PlaylistStream.hxx
+++ b/src/playlist/PlaylistStream.hxx
@@ -13,8 +13,10 @@ class Path;
 /**
  * Opens a playlist from a local file.
  *
+ * Throws on error.
+ *
  * @param path the path of the playlist file
- * @return a playlist, or nullptr on error
+ * @return a playlist, or nullptr if the file is not supported
  */
 std::unique_ptr<SongEnumerator>
 playlist_open_path(Path path, Mutex &mutex);
@@ -22,8 +24,10 @@ playlist_open_path(Path path, Mutex &mutex);
 /**
  * Opens a playlist from a remote file.
  *
+ * Throws on error.
+ *
  * @param uri the absolute URI of the playlist file
- * @return a playlist, or nullptr on error
+ * @return a playlist, or nullptr if the file is not supported
  */
 [[gnu::nonnull]]
 std::unique_ptr<SongEnumerator>