Skip to content

[BUG] LNbits >= 1.0: ISO 8601 time/expiry parsed as unix seconds, paid admissions never confirmed #927

Closed

Description

@Perlover

Describe the bug
With LNbits >= 1.0 as the payments processor, paid admissions are never confirmed and expired invoices stay pending forever.

LNbits 1.x returns details.time and details.expiry from GET /api/v1/payments/{payment_hash} as ISO 8601 strings (e.g. "2025-10-11T15:24:27+00:00"); LNbits 0.x returned unix seconds. LNbitsPaymentsProcessor still does new Date(data.details.time * 1000) / new Date(data.details.expiry * 1000), which yields Invalid Date for strings. As a result:

  • PaymentsService.confirmInvoice → InvoiceRepository.confirmInvoice calls confirmedAt.toISOString() → RangeError: Invalid time value, so a user who paid the admission invoice is not admitted (both from the /callbacks/lnbits webhook and from the maintenance worker poll);
  • isExpiredInvoice() is false for an invalid expiresAt, so unpaid invoices that LNbits still knows are re-saved as pending on every maintenance pass and never retired.

To Reproduce

  1. Run nostream with payments.enabled: true, payments.processor: lnbits against LNbits 1.x (seen with 1.5.6).
  2. Request an admission invoice at /invoices and pay it.
  3. The invoice is not confirmed and the pubkey is not admitted; unpaid invoices past their expiry remain pending in the invoices table.

Unit-level reproduction: feed invoiceResponse({ data: { paid: true }, details: { time: '2025-10-11T15:24:27+00:00' } }) to LNbitsPaymentsProcessor.getInvoice() — confirmedAt is Invalid Date.

Expected behavior
Dates from LNbits are parsed correctly whether they come as unix seconds (LNbits < 1.0) or ISO 8601 strings (LNbits >= 1.0); paid invoices get confirmed, expired ones get retired.

System

  • OS: Ubuntu 22.04
  • Platform: docker (compose)
  • Version: nostream 3.4.1 (same code in 2.1.0 and current main); LNbits 1.5.6

Logs
On 3.4.1 after the upgrade, 15 old unpaid invoices that LNbits still knows were re-saved as pending every minute; with the fix applied they were retired as expired on the next maintenance pass.

Additional context
I have a small fix with unit tests ready (accept both a number and an ISO string in the LNbits processor) and will open a PR referencing this issue.

Activity

  1. Perlover commented on Oct 22, 2026

    @Perlover
    ContributorAuthor

    The fix is ready, but GitHub does not let me open a pull request here ("does not have the correct permissions to execute CreatePullRequest" — PR creation seems limited to prior contributors).

    Branch: https://github.com/Perlover/nostream/tree/fix/lnbits-iso-dates
    Diff against main: main...Perlover:nostream:fix/lnbits-iso-dates

    Single commit 5ffad56 — fix(payments): parse ISO 8601 time/expiry returned by LNbits >= 1.0:

    • src/payments-processors/lnbits-payment-processor.ts: a toDate helper that accepts unix seconds (LNbits < 1.0) or an ISO 8601 string (LNbits >= 1.0), used for time/expiry in getInvoice and createInvoice;
    • two unit tests (ISO time/expiry → EXPIRED with exact dates; paid invoice with ISO time → valid confirmedAt). Without the fix they fail with expected 'pending' to equal 'expired' and RangeError: Invalid time value; with it all tests in the file pass;
    • a patch changeset.

    Build, biome lint and biome format are clean. Running in production on 3.4.1 + LNbits 1.5.6: stuck pending invoices were retired as expired on the next maintenance pass.

    If you can allow the PR (or cherry-pick the commit), that would close this issue.

  2. cameri commented on Oct 23, 2026

    @cameri
    Owner

    Thank you for opening this issue. Opening PRs is closed at this time to protect Nostream from the onslaught of AI (we are not against it, but my maintainer's time is limited as you can imagine).
    I will open a PR cherry-picking your fix soon and crediting you.

  3. chappie-daemon commented on Oct 23, 2026

    @chappie-daemon
    Collaborator

    Cherry-picked your commit 5ffad56 onto current main as #943, since GitHub would not let your account open the PR. Your authorship is intact on the commit (Perlover <perlover@perlover.com>) and the change is unmodified.

    I confirmed the bug reproduces on the branch before the fix: with the source reverted, both tests you added fail with expected 'pending' to equal 'expired' and RangeError: Invalid time value, exactly as your issue described. With the fix, all 5 pass, biome lint/format are clean, and tsc reports no errors in the changed file.

    Thanks for the diagnosis and the unit-level reproduction — that made this quick to verify rather than guess at.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions