UpStore

Odoo 19: "A css error occured, using an old style to render this page"

· Odoo, Troubleshooting

Odoo 19: "A css error occured, using an old style to render this page"

Odoo 19: “A css error occured, using an old style to render this page”

Chasing a $black SCSS error back to a missing Python dependency.

The symptom

After bringing up an Odoo 19 staging server, the login page rendered unstyled and the browser console showed:

Error: Undefined variable: "$black".
        on line 1472:23 of /stdin
This error occurred while compiling the bundle 'web.assets_frontend'

Odoo itself put a banner at the bottom of the page:

A css error occured, using an old style to render this page.

Odoo login page rendering with the unstyled 'old style' fallback, the 'Style error. The style compilation failed.' message, and the red 'A css error occured, using an old style to render this page' banner

That banner is Odoo’s fallback: when an SCSS asset bundle fails to compile, it serves a stripped-down stylesheet instead. So the real problem wasn’t “broken CSS” — it was a bundle that wouldn’t compile.

TL;DR

The frontend SCSS bundle references $black before it’s defined. In a healthy install, the html_editor module supplies that definition. On this server html_editor was not installed — because it failed to load with ImportError: bs4. And bs4 failed because the Python dependencies had been installed system-wide (with --break-system-packages), leaving a half-broken beautifulsoup4 and an aborted requirements.txt run. The fix was a proper virtualenv.

The investigation

1. Rule out the custom addons

The custom modules injected nothing into frontend assets and contained no SCSS. Not them.

2. Rule out the SCSS compiler

Odoo 19 compiles SCSS with libsass, pinned to 0.22.0. The server had exactly that. Same compiler + intact core source → it should compile. So the difference had to be in the bundle contents, not the tooling.

3. Read the bundle order

$black is used in core’s bootstrap_overridden_frontend.scss, but that file only uses it — it never defines it. In web.assets_frontend the order is:

_assets_helpers          → (primary/secondary variables)
_assets_frontend_helpers → bootstrap_overridden_frontend.scss   ← USES $black
pre_variables.scss                                              ← DEFINES $black (too late!)

So who legitimately defines $black early enough? Grepping the codebase, the answer was html_editor:

# html_editor/__manifest__.py
'web._assets_frontend_helpers': [
    ('prepend', 'html_editor/static/src/scss/bootstrap_overridden.scss'),
],

html_editor prepends a $black definition ahead of the file that needs it. It’s auto_install: True, so on a normal install it’s always present and the bundle compiles. The error’s file list contained only core files — no html_editor contribution. That was the smoking gun.

4. Check module state

Sure enough:

 html_editor | uninstalled
 mail        | uninstalled
 portal      | uninstalled
 web         | installed

5. Try to install it — and find the real root cause

A plain install attempt “succeeded silently” (its logs were being swallowed by a misconfigured logfile). Forcing logs to the screen revealed:

CRITICAL  Couldn't load module html_editor
...
  File ".../html_editor/models/diff_utils.py", line 6, in <module>
    from bs4 import BeautifulSoup
ImportError: Could not load the module 'bs4' to patch

html_editor needs BeautifulSoup (bs4), and it couldn’t be imported — even though pip reported it as already satisfied. The package metadata existed, but the package was broken/partial. On top of that, re-running requirements.txt aborted midway:

ERROR: Cannot uninstall cryptography 41.0.7, RECORD file not found.
       The package was installed by debian.

That’s the classic system-Python mess: pip packages installed with --break-system-packages colliding with apt-managed ones, leaving half-installed dependencies and a requirements run that never completes.

Root cause

The Python dependencies were installed into the system interpreter, not an isolated environment. That left beautifulsoup4 broken → html_editor couldn’t load → html_editor stayed uninstalled → nothing defined $black for the frontend bundle → web.assets_frontend failed to compile → “old style” fallback on every page.

The fix: give Odoo its own virtualenv

A venv gives Odoo an isolated site-packages that pip fully controls — no --break-system-packages, no apt-vs-pip conflicts, no half-installed packages.

Create the venv and install dependencies

# (example paths: service user 'odoo', home '/opt/odoo')
sudo apt install -y python3-venv python3-dev build-essential \
  libpq-dev libxml2-dev libxslt1-dev libldap2-dev libsasl2-dev \
  libjpeg-dev zlib1g-dev libffi-dev

sudo -u odoo python3 -m venv /opt/odoo/venv
sudo -u odoo /opt/odoo/venv/bin/pip install --upgrade pip wheel
sudo -u odoo /opt/odoo/venv/bin/pip install -r /opt/odoo/odoo-server/requirements.txt

Note: inside a venv you do not need --break-system-packages — a venv isn’t an externally-managed environment, so the flag is a harmless no-op there.

Point the service at the venv

There are two service styles depending on how you installed Odoo.

Option 1 — SysV init script (/etc/init.d/<service>, as produced by the popular Yenthe install script). Change two lines so the venv’s python is the executable and odoo-bin becomes its first argument:

# before
DAEMON=/opt/odoo/odoo-server/odoo-bin
DAEMON_OPTS="-c $CONFIGFILE"

# after
DAEMON=/opt/odoo/venv/bin/python3
DAEMON_OPTS="/opt/odoo/odoo-server/odoo-bin -c $CONFIGFILE --logfile /var/log/odoo/odoo-server.log"

On modern Ubuntu, systemd wraps the init script automatically, so after editing run:

sudo systemctl daemon-reload

Option 2 — systemd unit (ExecStart). Point it at the venv interpreter:

ExecStart=/opt/odoo/venv/bin/python3 /opt/odoo/odoo-server/odoo-bin \
  --config /etc/odoo.conf \
  --logfile /var/log/odoo/odoo-server.log
sudo systemctl daemon-reload

Install the module and restart

# make sure the logfile directory exists
sudo mkdir -p /var/log/odoo && sudo chown odoo: /var/log/odoo

sudo service odoo-server stop

# one-off install using the venv interpreter
sudo -u odoo /opt/odoo/venv/bin/python3 /opt/odoo/odoo-server/odoo-bin \
  -c /etc/odoo.conf -d odoo \
  -i html_editor --stop-after-init --logfile=/dev/stdout --log-level=info

sudo service odoo-server start

A clean run now shows Loading module html_editorModules loaded. with no CRITICAL, the process runs under /opt/odoo/venv/bin/python3, and a hard reload of the login page renders normally — the $black error and the “old style” banner are gone.

Lessons

  • “A css error occured, using an old style to render this page” = an SCSS asset bundle failed to compile. Reload with ?debug=assets or read the server log for the real error.
  • Undefined variable: $black in web.assets_frontend usually means a module that defines the variable (here html_editor) isn’t installed — not a compiler bug.
  • A frontend SCSS error can trace all the way back to a missing/broken Python package blocking an auto_install module from loading.
  • Install Odoo’s Python dependencies in a virtualenv, never system-wide with --break-system-packages. It’s the difference between pip owning the environment and fighting apt over it.
  • If a module install looks like it “did nothing”, check your logfile setting — errors may be going to a file (or a directory that doesn’t exist) instead of your terminal.

Running Odoo on your own infrastructure? Self-hosting Odoo means owning exactly this class of problem — asset bundles, Python environments, module dependencies, and the silent failures in between. If you’d rather not fight apt against pip at 2am, we implement and maintain Odoo for Malaysian businesses end to end — from a clean, upgrade-safe install to the tailoring that makes it fit. See Odoo ERP & customization in Malaysia.

More on Odoo Customization

Ready to streamline your operations?

Talk to our team about how UpStore can help your business.

    navigate open Esc close