ElementsProject / ElementsProject/lightning

xpay: "Could not create payment onion: path too long!" on BOLT12 offers with large embedded TLVs (has FIXME)

Open
#9,156 8 comments 1 reaction 0 assignees View on GitHub
pay-plugin plugin routing Type::Bug
Dominant language
C
Stars
3.1k
Forks
1k
Avg merge
4d 10h
Merged PRs (30d)
13

Description

### Summary

When using `xpay` (and the surrounding payment plugins: renepay, askrene) to pay certain BOLT12 offers that carry large amounts of embedded data in their TLVs, xpay fails during onion construction with:

```
Could not create payment onion: path too long!
```

(with RPC error code 209 / `PAY_UNSPECIFIED_ERROR`).

The failure originates here:

https://github.com/ElementsProject/lightning/blob/master/plugins/xpay/xpay.c (around the `do_inject` function)

```c
onion = create_onion(tmpctx, attempt, effective_bheight);
/* FIXME: Handle this better! */
if (!onion) {
payment_give_up(aux_cmd, attempt->payment, PAY_UNSPECIFIED_ERROR,
"Could not create payment onion: path too long!");
return command_still_pending(aux_cmd);
}
```

The underlying cause is `create_onionpacket(...)` returning NULL when `sphinx_path_payloads_size(sp) > ROUTING_INFO_SIZE`.

### Observed symptoms

- The BOLT12 offers in question contain long `invoice` / offer metadata (hundreds of bytes of extra TLV data for payout tracking / recipient verification). This inflates the final serialized onion far beyond what a "normal length" route would use.
- Route selection still proposes paths that later fail at the onion creation step.
- In the same payment attempts we also saw many `plugin-cln-renepay` failures with `code=202 "Malformed error reply"` and very large `onionreply` blobs.
- The node in question has very low channel count (only 2 active channels), which makes longer routes more common and the size limit easier to hit.
- The error was surfaced to end users via a higher-level plugin (`cln4go-plugin` doing custom "ocean-pay" logic) during real production Lightning payout processing.

### Steps to reproduce (conceptual)

1. Have a node with limited channels.
2. Attempt to pay a BOLT12 offer (`lni1...` / `lno1...`) whose encoded invoice/offer contains substantial extra TLV data.
3. xpay / the payment attempt reaches `create_onion` → size check fails.

### Expected behavior

- Either the route finder (askrene + xpay/renepay) should account for the *final serialized onion size* (including extra BOLT12 TLVs) when selecting paths, or
- xpay should handle the failure more gracefully (try a shorter route / more parts / clearer error with hop count + payload size, etc.), and
- the error message returned to the caller / user should be more actionable than the current generic "path too long".

### Version / environment

- Observed on a custom/modded build based on v26.04 (and v25 on another instance)
- Using `xpay`, `renepay`, `askrene`, plus custom BOLT12 handling on top (`cln4go-plugin`)
- Full log excerpts and the exact failing offer (with tracking ID in the offer description) available if needed for reproduction.

### Additional context

This was discovered while debugging a user-facing payout error on an experimental Ocean.xyz Lightning node (`el.ocean.xyz`).

The `FIXME: Handle this better!` comment suggests this case was already known to be suboptimal.

Contributor guide

No contributing guide indexed for this repository

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.