Follow-up to #290 — same class of bug, different code path.
list_payments() in cln_jrpc.py unconditionally indexed p["bolt11"] for any
incomplete payment, causing a KeyError -> the function returned None and
then list_all_tx() crashed with `TypeError: 'NoneType' object is not
iterable`, returning HTTP 500 to the Transactions view.
CLN's `listpays` does not include `bolt11` for keysend payments or for
BOLT12 offer payments, so any node that has ever made one of those will
hit this on every Transactions load.
Fix: guard the bolt11 decode the same way #290 guards invoice fields —
only decode when bolt11 is present, and fall back to amount_sent_msat
when neither bolt11 nor amount_msat are available, so the payment still
shows up in the list.
Reproduced on RaspiBlitz v1.12.1 with Core Lightning v25.12.1 and a
keysend payment in history.
Extract the Python virtualenv build into `mkBlitzApi { pkgs, python ?
null }` and expose it as `lib.mkBlitzApi`. Rewrite `overlays.default`
to call the builder against the consumer's `prev` instead of pulling
from `self.packages.${system}` (which captured this flake's pinned
nixpkgs at flake-eval time and shut consumer overlays out of the
build hook).
Motivation: NixBlitz pulls blitz-api's flake via `builtins.getFlake`
to keep the plugin self-contained. Without a pkgs-agnostic builder,
the operator's nixpkgs overlays (Pi 5 jemalloc page-size patch and
similar platform fixes) couldn't reach blitz-api's build, so the
package would either fail to compile on Pi 5 or silently link
against this flake's pinned nixpkgs and pull a second snapshot of
glibc / openssl / etc. into the operator's closure.
The `packages.${system}.${name}` attribute is preserved as a
convenience pre-built using this flake's pinned nixpkgs; consumers
that want consumer-pkgs builds should use `overlays.default` or
`lib.mkBlitzApi` directly.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
`ln` is only bound to LnNode() when `BAPI_LN_NODE != "none"`. Every
`await ln.X()` call in this file therefore NameErrors when the
operator runs in bitcoin-only mode.
The most-hit caller is NativePythonSystem.get_system_info() at
app/system/impl/native_python.py:32, which always reads
`lninfo.alias` and `lninfo.color` to populate SystemInfo. The
NameError there breaks the SSE warmup pipeline
(get_full_client_warmup_data_bitcoinonly in app/api/warmup.py:116):
warmup_new_connections() — calls get_full_client_warmup_data_bitcoinonly()
→ get_system_info() (via NativePythonSystem)
→ get_ln_info()
→ NameError: name 'ln' is not defined
The exception bubbles into the asyncio.gather(), which means new
SSE subscribers in bitcoin-only mode never receive `btc_info` /
`system_info` / `installed_app_status`. Their dashboards stay empty
forever (only periodic `hardware_info` and `ping` events flow,
because those run on separate gather loops).
Two fixes in this commit:
1. Return a stub LnInfo from get_ln_info() when ln_node == "none".
All required fields filled with empty strings / zeros; the stub
round-trips through any caller that reads alias/color/num_*
without error. Other ln-method callers (get_wallet_balance,
list_invoices, ...) keep their original behavior — they'll only
ever fire from LN-aware code paths anyway.
2. Drop the duplicate `if ln_node != "none": ln = LnNode()` block
at lines 69-70 (clearly a merge artifact).
Operator workaround used until this lands: enable lnd. After this
fix, bitcoin-only mode works end-to-end against the nixblitz
plugin streamer.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- Add async-timeout as a direct dependency in pyproject.toml to fix
ModuleNotFoundError on systems with Python < 3.11.3 (e.g. Raspberry Pi).
- Switch to universal requirements generation in Makefile and
requirements.txt to include platform-specific markers and conditional
dependencies.
- Update uv.lock to reflect dependency changes.
This resolves a crash where redis-py attempted to import async_timeout,
which was missing because it was pruned during requirements generation
on a newer Python version.
Fixes#129, #128, and addresses part of raspiblitz/raspiblitz#3182
BOLT12 offers, keysend payments, and certain CLN invoice types don't
always include all fields that the API expects, causing KeyError
exceptions that crash the web interface.
Changes:
- Modified Invoice.from_cln_json() to use .get() with safe defaults
for all potentially missing fields (bolt11, amount_msat, payment_hash,
description, label, status, etc.)
- Added fallback logic for amount_msat to use amount_received_msat
when the primary field is missing
- Enhanced InvoiceState.from_cln_json() to handle unknown/missing
statuses gracefully with logging instead of raising exceptions
This allows the web interface to display all CLN invoices including
BOLT12 payments from services like OCEAN mining pool, while preserving
all existing payment data for standard BOLT11 invoices.
Tested on RaspiBlitz v1.12.0 with Core Lightning and OCEAN mining
pool BOLT12 payouts.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
This is a feature that allows to fetch the app status via a celery
task which stores the result in the Redis database and notifies the API
of the change. The API sends a notification to connected clients via the
SSE mechanism.
Using a background task allows to avoid crashing the whole API if the
script call fails.
The by default the cache is refreshed every 30 minutes. This can be
changed by setting the `BAPI_APP_STATUS_UPDATE_INTERVAL_MIN` environment
variable.
refs #123
- add a result type similar to the Rust Result type from
https://github.com/rustedpy/result
- add a Report class to propagate error information back on the stack
with return types instead of exceptions
refs #123
If the environment variable BAPI_ENV_PATH is set, the config system will
try to read configs from the given path instead of .env in pwd
If no file is found .env in pwd will be used as a fallback
Env variables will always override settings in .env files.