diff --git a/CHANGELOG.rst b/CHANGELOG.rst
index b6e1e530b39b36a9c04f2ca42235bcc8a1b532e9..3457ee9c9e36be38e6ef09dad4020c212eee1e96 100644
--- a/CHANGELOG.rst
+++ b/CHANGELOG.rst
@@ -9,6 +9,12 @@ and this project adheres to `Semantic Versioning`_.
 Unreleased
 ----------
 
+Fixed
+~~~~~
+
+* [Docker] The build could silently continue even if frontend bundling failed, resulting
+  in an incomplete AlekSIS frontend app.
+
 `3.1.2`_ - 2023-07-05
 ---------------------
 
diff --git a/aleksis/core/management/commands/vite.py b/aleksis/core/management/commands/vite.py
index 57370441b37a9db241a8a8a0bebbd8f8f00f5753..747f328ea82060b2b0148d9c928a498e018cefc9 100644
--- a/aleksis/core/management/commands/vite.py
+++ b/aleksis/core/management/commands/vite.py
@@ -1,6 +1,7 @@
 import os
 
 from django.conf import settings
+from django.core.management.base import CommandError
 
 from django_yarnpkg.management.base import BaseYarnCommand
 from django_yarnpkg.yarn import yarn_adapter
@@ -26,4 +27,6 @@ class Command(BaseYarnCommand):
             yarn_adapter.install(settings.YARN_INSTALLED_APPS)
 
         # Run Vite build
-        run_vite([options["command"]])
+        ret = run_vite([options["command"]])
+        if ret != 0:
+            raise CommandError("yarn command failed", returncode=ret)
diff --git a/aleksis/core/util/frontend_helpers.py b/aleksis/core/util/frontend_helpers.py
index 5d343acc0533a2509077c0f0d15ca0bc8d1823f9..885ac39fd51833c55ce072cc8a425991cfea7db2 100644
--- a/aleksis/core/util/frontend_helpers.py
+++ b/aleksis/core/util/frontend_helpers.py
@@ -49,7 +49,7 @@ def write_vite_values(out_path: str) -> dict[str, Any]:
         json.dump(vite_values, out)
 
 
-def run_vite(args: Optional[Sequence[str]] = None) -> None:
+def run_vite(args: Optional[Sequence[str]] = None) -> int:
     args = list(args) if args else []
 
     config_path = os.path.join(settings.BASE_DIR, "aleksis", "core", "vite.config.js")
@@ -64,7 +64,7 @@ def run_vite(args: Optional[Sequence[str]] = None) -> None:
     log_level = {"INFO": "info", "WARNING": "warn", "ERROR": "error"}.get(log_level, "silent")
     args += ["-l", log_level]
 
-    yarn_adapter.call_yarn(["run", "vite"] + args)
+    return yarn_adapter.call_yarn(["run", "vite"] + args)
 
 
 def get_language_cookie(code: str) -> str: