get_current_profile_id: catch RuntimeError so background callers don't crash

Reproduced on the personalized playlist pipeline: selecting Fresh Tape
(or any kind) and running the automation surfaced
"Working outside of application context" in the UI.

Root cause: `get_current_profile_id` reads Flask's `g.profile_id` and
only catches `AttributeError`. Outside a request — automation engine,
sync threads, watchlist scanner — `g` raises `RuntimeError` instead,
so the except misses and the handler dies.

Mirrored playlist pipeline never hit this because it hardcodes
profile_id=1 in its sync call. The personalized pipeline calls
`deps.get_current_profile_id()` from a background thread, which is
what tripped the bug. Fresh Tape's generator also resolves the
profile via the same function — same path, same crash.

Fix: broaden the except to `(AttributeError, RuntimeError)` in all
three copies of the helper (`web_server.py`, `core/artists/map.py`,
`core/discovery/hero.py`). All three now safely degrade to profile_id=1
(admin profile) when called outside a request context — matches the
existing intent that single-admin installs Just Work.

No test changes — the existing pipeline tests stub the helper, so
they never exercised the bug. The fix is in the layer above the
stubs.
pull/614/head
Broque Thomas 1 week ago
parent 877d0e7d81
commit 08725094db

@ -20,10 +20,14 @@ logger = logging.getLogger(__name__)
def get_current_profile_id() -> int:
"""Mirror of web_server.get_current_profile_id — uses Flask g."""
"""Mirror of web_server.get_current_profile_id — uses Flask g.
Catches RuntimeError too because reading `g` outside a request
context raises that (not AttributeError) happens when this is
called from background threads (sync, automation, scanners)."""
try:
return g.profile_id
except AttributeError:
except (AttributeError, RuntimeError):
return 1

@ -17,10 +17,14 @@ logger = logging.getLogger(__name__)
def get_current_profile_id() -> int:
"""Mirror of web_server.get_current_profile_id — uses Flask g."""
"""Mirror of web_server.get_current_profile_id — uses Flask g.
Catches RuntimeError too because reading `g` outside a request
context raises that (not AttributeError) happens when this is
called from background threads (sync, automation, scanners)."""
try:
return g.profile_id
except AttributeError:
except (AttributeError, RuntimeError):
return 1

@ -474,10 +474,16 @@ def _add_discover_cache_headers(response):
def get_current_profile_id() -> int:
"""Get the current profile ID from Flask g context or default to 1"""
"""Get the current profile ID from Flask g context or default to 1.
Background callers (automation engine, sync threads, watchlist
scanner) have no request context, so `g.profile_id` raises
`RuntimeError("Working outside of application context")` rather
than `AttributeError`. Catch both so non-request callers degrade
to the admin profile instead of crashing the handler."""
try:
return g.profile_id
except AttributeError:
except (AttributeError, RuntimeError):
return 1

Loading…
Cancel
Save