Skip to content

Intermittent get-invoice timeouts and pay-invoice failures when paying Phoenix BOLT12 offers from BOLT12 Pay (self-hosted app on Umbrel) #257

@Alex71btc

Description

@Alex71btc

Bug: Intermittent get-invoice timeouts and pay-invoice failures when paying Phoenix BOLT12 offers from BOLT12 Pay (self-hosted app on Umbrel)

Describe the bug

I am integrating LNDK into my self-hosted app BOLT12 Pay (Umbrel Community App / self-hosted Lightning payment and identity server). While testing payments to Phoenix-generated BOLT12 offers, I am seeing two related failure modes:

  1. get-invoice against the same offer is intermittent:

    • sometimes it returns a valid BOLT12 invoice
    • sometimes it fails with INVOICE_TIMEOUT
  2. even when get-invoice succeeds and returns a valid invoice, a follow-up pay-invoice against that exact invoice can still fail with:

    • ERROR (PAYMENT_FAILURE): Payment failed

This makes it look like the problem is not only in the offer → invoice request step, but also in the actual payment of the returned blinded-path invoice.

Because this happens inside my BOLT12 Pay app integration, I wanted to report it here in case it is useful for LNDK interoperability and production hardening.


Context

I am building BOLT12 Pay, a self-hosted Lightning payment + identity server / Umbrel app that integrates:

  • BOLT12 offers via LNDK
  • BIP353 human-readable addresses
  • LNURL / Lightning Address fallback
  • BOLT11 fallback
  • self-hosted pay UI

So this bug affects a real app integration, not just ad-hoc CLI testing.
If you want to have a look at my implementation:
https://github.com/Alex71btc/lndk-pay
https://github.com/Alex71btc/umbrel-community-store


Environment

  • LNDK image/tag: alex71btc/lndk:stable-good-20260401
  • LNDK transport: local gRPC in container
  • Host setup: Umbrel, Docker
  • Caller app: BOLT12 Pay (self-hosted Umbrel app)
  • Target wallet/offers: Phoenix-generated BOLT12 offers
  • Network: bitcoin mainnet

LNDK CLI help in my environment shows support for:

  • pay-offer
  • get-invoice
  • pay-invoice
    with --response-invoice-timeout, --fee-limit, and --fee-limit-percent options.

What I tested

1) pay-offer directly

For the same Phoenix offer, pay-offer is flaky:

  • sometimes INVOICE_TIMEOUT
  • sometimes invoice is received and payment proceeds
  • sometimes the payment later fails

Relevant LNDK log pattern:

INFO lndk::server - Received a request: PayOfferRequest { ... amount: Some(1000000) ... }
...
ERROR lndk::offers::handler - Did not receive invoice in 15 seconds.

and in other runs:

INFO lndk::offers::handler - Successfully verified invoice for payment_id ...
DEBUG lndk::offers::handler - Payment paths found for invoice with payment_id ...: 1
DEBUG lndk::offers::handler - Attempting to pay invoice with introduction node Some("03864ef025fde8fb587d989186ce6a4a186895ee44a926bfc370e2c366597a3f8f")
TRACE lndk::offers::lnd_requests - Routes found 1...
TRACE lndk::offers::lnd_requests - Sent payment using preimage  using attempt_id ... with status 2. failed with reason: 15.
ERROR lndk::offers::handler - Failed to track payment for payment_id ...

2) get-invoice separately

I then separated the flow and ran get-invoice manually against the same offer.

This is also intermittent:

  • sometimes ERROR (INVOICE_TIMEOUT): Invoice request timed out after 30 seconds
  • sometimes it successfully returns Invoice: GetInvoiceResponse { invoice_hex_str: "...", invoice_contents: Some(...) }

Example command:

lndk-cli \
  --network=bitcoin \
  --grpc-host=https://127.0.0.1 \
  --grpc-port=7000 \
  --cert-path=/data/lndk/tls-cert.pem \
  --macaroon-path=/lnd/data/chain/bitcoin/mainnet/admin.macaroon \
  get-invoice "<offer>" 1000000 --response-invoice-timeout 30

3) pay-invoice against a successfully returned invoice

Most important finding:

Even when get-invoice succeeds and returns a valid invoice, the following can still fail:

lndk-cli \
  --network=bitcoin \
  --grpc-host=https://127.0.0.1 \
  --grpc-port=7000 \
  --cert-path=/data/lndk/tls-cert.pem \
  --macaroon-path=/lnd/data/chain/bitcoin/mainnet/admin.macaroon \
  pay-invoice "<invoice_hex>" 1000000 --fee-limit 50000

Result:

ERROR (PAYMENT_FAILURE): Payment failed

This seems important because it suggests the issue is not only in the offer/invoice request phase. It also affects payment of a successfully retrieved BOLT12 invoice.


Why I think this may be an LNDK / blinded payment / interop issue

The returned invoices include blinded payment paths, e.g. values like:

  • blinded_pay_info
  • fee_base_msat: 1000
  • fee_proportional_millionths: 100
  • htlc_minimum_msat: 1000
  • htlc_maximum_msat: 2000000

In logs, LNDK clearly reaches the stage where it:

  • verifies the invoice
  • finds payment paths
  • attempts payment
  • then fails with status 2 / reason: 15 or generic PAYMENT_FAILURE

So this does not look like a bug in my UI or a DNS/BIP353/LNURL problem. The same issue reproduces directly through lndk-cli.


Additional observations

  • Very small test amounts have sometimes succeeded.
  • 1000000 msat / 1000 sats is flaky.
  • In some runs, Phoenix/BOLT12 offer retrieval works immediately.
  • In other runs, the exact same command times out.
  • In some runs, invoice retrieval succeeds but actual payment still fails.

This makes the behavior look intermittent and possibly path / peer / blinded-path related.


Similar issue

I also noticed an existing issue that looks related:

My case is not CLN on the receiver side, but the pattern feels similar because there are intermittent offer/invoice exchange failures and then payment failures around BOLT12 / blinded paths.


Expected behavior

For a valid Phoenix BOLT12 offer:

  • get-invoice should reliably return an invoice
  • pay-invoice for that returned invoice should reliably succeed
  • pay-offer should be equivalent to the above combined flow and be reliable as well

Actual behavior

For the same valid Phoenix BOLT12 offer:

  • get-invoice sometimes times out
  • sometimes returns a valid invoice
  • pay-invoice against a returned invoice can still fail with PAYMENT_FAILURE

Reproduction summary

  1. Start LNDK and connect it to LND on Umbrel.

  2. Obtain a Phoenix-generated BOLT12 offer.

  3. Run:

    lndk-cli ... get-invoice "<offer>" 1000000 --response-invoice-timeout 30
  4. Repeat multiple times.

  5. Observe:

    • sometimes INVOICE_TIMEOUT
    • sometimes valid invoice returned
  6. When invoice is returned, run:

    lndk-cli ... pay-invoice "<invoice_hex>" 1000000 --fee-limit 50000
  7. Observe:

    • PAYMENT_FAILURE

If useful, I can provide

  • full sanitized CLI command history
  • the exact offer strings used
  • full LNDK logs
  • details from my BOLT12 Pay Umbrel app integration
  • side-by-side traces from app flow vs direct CLI flow

Thanks — I’m reporting this because I think it matters for real-world BOLT12 app integrations, and BOLT12 Pay is exactly the kind of self-hosted app that depends on this working reliably.
I’m happy to test patched images or specific branches from this issue in my Umbrel-based BOLT12 Pay setup.

If helpful, I can also open a follow-up issue in my app repo documenting how this affects real-world self-hosted BOLT12 UX.
This may be related in spirit to #103, although my receiver side here is Phoenix rather than CLN. The common pattern seems to be unreliable offer/invoice exchange and/or failures around blinded-path payments.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions