diff --git a/src/libcmd/command.cc b/src/libcmd/command.cc
index 569c4b9e4c25fab9ec7c37fca179262c6e2b5913..6777b23be5cb22d7dcd6977f51a04157190f1a04 100644
--- a/src/libcmd/command.cc
+++ b/src/libcmd/command.cc
@@ -188,7 +188,7 @@ void MixProfile::updateProfile(const BuiltPaths & buildables)
     }
 
     if (result.size() != 1)
-        throw Error("'--profile' requires that the arguments produce a single store path, but there are %d", result.size());
+        throw UsageError("'--profile' requires that the arguments produce a single store path, but there are %d", result.size());
 
     updateProfile(result[0]);
 }
diff --git a/src/libexpr/attr-path.cc b/src/libexpr/attr-path.cc
index 9dd557205c907de995d74aed4f21fbbfd48d1123..867eb13a5da5c7cb405febd529a682d92d780352 100644
--- a/src/libexpr/attr-path.cc
+++ b/src/libexpr/attr-path.cc
@@ -19,7 +19,7 @@ static Strings parseAttrPath(std::string_view s)
             ++i;
             while (1) {
                 if (i == s.end())
-                    throw Error("missing closing quote in selection path '%1%'", s);
+                    throw ParseError("missing closing quote in selection path '%1%'", s);
                 if (*i == '"') break;
                 cur.push_back(*i++);
             }
@@ -116,14 +116,14 @@ Pos findDerivationFilename(EvalState & state, Value & v, std::string what)
 
     auto colon = pos.rfind(':');
     if (colon == std::string::npos)
-        throw Error("cannot parse meta.position attribute '%s'", pos);
+        throw ParseError("cannot parse meta.position attribute '%s'", pos);
 
     std::string filename(pos, 0, colon);
     unsigned int lineno;
     try {
         lineno = std::stoi(std::string(pos, colon + 1));
     } catch (std::invalid_argument & e) {
-        throw Error("cannot parse line number '%s'", pos);
+        throw ParseError("cannot parse line number '%s'", pos);
     }
 
     Symbol file = state.symbols.create(filename);
diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc
index c078bf4a1771482a4c70b33927fe4d0c04208168..fe25d894a7dacf091ec595932d74bde742ff11b9 100644
--- a/src/libexpr/eval.cc
+++ b/src/libexpr/eval.cc
@@ -920,7 +920,7 @@ void EvalState::evalFile(const Path & path_, Value & v, bool mustBeTrivial)
         // computation.
         if (mustBeTrivial &&
             !(dynamic_cast<ExprAttrs *>(e)))
-            throw Error("file '%s' must be an attribute set", path);
+            throw EvalError("file '%s' must be an attribute set", path);
         eval(e, v);
     } catch (Error & e) {
         addErrorTrace(e, "while evaluating the file '%1%':", path2);
diff --git a/src/libutil/url.cc b/src/libutil/url.cc
index c1bab866c1585f5089314f2508e0eb4e7e8ebdd3..f6232d255e180ebb2ec4e4adff99ecc17d11ea33 100644
--- a/src/libutil/url.cc
+++ b/src/libutil/url.cc
@@ -32,7 +32,7 @@ ParsedURL parseURL(const std::string & url)
         auto isFile = scheme.find("file") != std::string::npos;
 
         if (authority && *authority != "" && isFile)
-            throw Error("file:// URL '%s' has unexpected authority '%s'",
+            throw BadURL("file:// URL '%s' has unexpected authority '%s'",
                 url, *authority);
 
         if (isFile && path.empty())