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)
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)
- Have a node with limited channels.
- Attempt to pay a BOLT12 offer (
lni1... / lno1...) whose encoded invoice/offer contains substantial extra TLV data.
- 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.
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:(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_injectfunction)The underlying cause is
create_onionpacket(...)returning NULL whensphinx_path_payloads_size(sp) > ROUTING_INFO_SIZE.Observed symptoms
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.plugin-cln-renepayfailures withcode=202 "Malformed error reply"and very largeonionreplyblobs.cln4go-plugindoing custom "ocean-pay" logic) during real production Lightning payout processing.Steps to reproduce (conceptual)
lni1.../lno1...) whose encoded invoice/offer contains substantial extra TLV data.create_onion→ size check fails.Expected behavior
Version / environment
xpay,renepay,askrene, plus custom BOLT12 handling on top (cln4go-plugin)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.