#11176·lnd

[bug]: AMP sub-invoice accepts HTLCs after cancellation

Author: abhayguptasCreated Sep 6, 2026Updated Sep 6, 2026
Labelsbugneeds triage

Pre-Submission Checklist

  • I have searched the existing issues and believe this is a new bug.
  • I am not asking a question about how to use lnd, but reporting a bug (otherwise open a discussion).

LND Version

0.21.99-beta

LND Configuration

Bug Description

An AMP sub-invoice that has already been canceled can still accept a new HTLC for the same setID while the parent invoice remains open.

This happens because updateMpp() checks the parent invoice state but does not check the state of the specific AMP sub-invoice.

Expected Behavior

A new HTLC for an AMP setID that is already in HtlcStateCanceled should be rejected immediately with ResultInvoiceAlreadyCanceled.

Current Behavior

The HTLC is accepted/deferred and can remain pending until the invoice eventually expires.

Reproduction

  1. Create an AMP invoice.
  2. Send a partial AMP payment so the specific setID becomes canceled.
  3. Send another HTLC for the same setID.
  4. The new HTLC is accepted instead of being rejected immediately.

Background

This behavior was previously noted in invoices/invoiceregistry_test.go with the following TODO:

TODO(ziggie): Fix this bug.

The existing test currently works around the issue by allowing the HTLC to remain pending until the MPP timeout.

Proposed Fix

Check the specific AMP sub-invoice state in updateMpp() after validating the invoice payment address.

If the setID is already HtlcStateCanceled, return ResultInvoiceAlreadyCanceled.

Testing

Update the existing regression test to verify the new immediate failure behavior and remove the existing expiry/timeout workaround.

Backend Version

Not applicable - this issue is in the invoice registry/state machine and does not depend on the Bitcoin backend.

Backend Configuration

Not applicable - the issue occurs in the invoice handling logic and does not depend on bitcoind/btcd configuration.

OS/Distribution

macOS (Darwin). Backend-independent issue in the LND invoice registry.

Bug Details & Steps to Reproduce

An AMP sub-invoice can accept a new HTLC after that specific AMP setID has already been canceled, as long as the parent invoice remains open.

The existing test testFailPartialAMPPayment documents this behavior and contains a TODO to fix it.

Steps to reproduce:

  1. Create an AMP invoice.
  2. Send a partial AMP payment so the specific setID becomes canceled.
  3. Send another HTLC for the same setID using the correct payment address.
  4. Observe that the new HTLC is accepted/deferred instead of being rejected immediately.

Expected Behavior

A new HTLC for an AMP setID that is already in HtlcStateCanceled should be rejected immediately with ResultInvoiceAlreadyCanceled.

The canceled AMP sub-invoice should not accept or persist the new HTLC. The parent invoice should remain open so that other AMP setIDs can still receive payments.

Debug Information

No response

Environment

No response