Created
June 2, 2026 22:16
-
-
Save vincenzopalazzo/073f3b7b438e03aa8c27b8c684093f7d to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| You are working in the OCEAN mining dashboard / payout codebase. | |
| Goal: | |
| Improve the Lightning payout error UX so users stop seeing vague messages like: | |
| "Unknown payout error, contact lightning@ocean.xyz" | |
| Most Lightning payout failures are temporary route/liquidity/reachability issues, and OCEAN retries automatically. The UI should classify the raw CLN/lightning error into a user-friendly category, show a clear status and action, hide raw technical details behind an expandable section, and only tell users to contact support after sensible thresholds. | |
| Context: | |
| Lightning payments can fail transiently because routing depends on channel liquidity, stale gossip, intermediary nodes, and pathfinding. Public research confirms that LN routes often fail because balances are private and network information can be stale; retries may succeed later. See: | |
| - Lightning payments use local graph knowledge, while channel balances are not public, so intermediary-hop failures are expected and retries are normal. | |
| - Empirical LN reliability studies show routing success depends on amount and stale network information. | |
| - BOLT onion routing means many failures happen along the route, not necessarily at OCEAN or the recipient wallet. | |
| Implementation requirements: | |
| 1. Find where dashboard / API currently renders or stores Lightning payout errors. | |
| Search for strings like: | |
| - "Unknown payout error" | |
| - "contact lightning@ocean.xyz" | |
| - "Latest lightning error" | |
| - "Raw error" | |
| - "cln err code" | |
| - "No route found" | |
| - "Timeout waiting for response" | |
| 2. Add a classifier for Lightning payout errors. | |
| Create a function similar to: | |
| classifyLightningError(rawError: string, context?: LightningErrorContext): LightningErrorCategory | |
| Suggested categories: | |
| TEMPORARY_ROUTE_OR_LIQUIDITY | |
| CUSTODIAL_WALLET_ROUTE_UNAVAILABLE | |
| SELF_HOSTED_ROUTE_OR_LIQUIDITY | |
| RECIPIENT_UNREACHABLE | |
| INVALID_BOLT12_OFFER | |
| KNOWN_CLN_PATH_TOO_LONG | |
| PAYOUT_PENDING_RETRYING | |
| UNKNOWN_BUT_RETRYING | |
| Suggested matching logic: | |
| KNOWN_CLN_PATH_TOO_LONG: | |
| - "Could not create payment onion: path too long" | |
| - "path too long" | |
| RECIPIENT_UNREACHABLE: | |
| - "Node unreachable" | |
| - "Timeout waiting for response" | |
| - "Unable to connect" | |
| - "no address known for peer" | |
| - "could not route or connect" | |
| - "cln err code: 1003" | |
| - "cln err code: `1003`" | |
| - "cln err code: 1005" | |
| - "cln err code: `1005`" | |
| INVALID_BOLT12_OFFER: | |
| - offer rejected | |
| - invalid offer | |
| - amount field in offer | |
| - signature verification failed | |
| - offer memo/address mismatch | |
| - BOLT12 field contains a Bitcoin address instead of an offer | |
| TEMPORARY_ROUTE_OR_LIQUIDITY: | |
| - "temporary_channel_failure" | |
| - "fee_insufficient" | |
| - "No route found" | |
| - "Could not find route" | |
| - "could not find a usable set of paths" | |
| - "Timed out after" | |
| - "Failed after" | |
| - "cln err code: 205" | |
| - "cln err code: `205`" | |
| - "cln err code: 209" | |
| - "cln err code: `209`" | |
| - "cln err code: 210" | |
| - "cln err code: `210`" | |
| If context indicates the user is using LEXE/CoinOS/another custodial wallet, map route/liquidity errors to: | |
| CUSTODIAL_WALLET_ROUTE_UNAVAILABLE | |
| If context indicates a self-hosted node, custom node pubkey, onion address, or Core Lightning node, map route/liquidity errors to: | |
| SELF_HOSTED_ROUTE_OR_LIQUIDITY | |
| Otherwise use: | |
| TEMPORARY_ROUTE_OR_LIQUIDITY | |
| 3. Add user-facing copy for each category. | |
| Do not show "contact lightning@ocean.xyz" as the default message. | |
| Copy: | |
| TEMPORARY_ROUTE_OR_LIQUIDITY | |
| Title: | |
| Lightning payout delayed — OCEAN will retry automatically | |
| Body: | |
| We could not find a working Lightning route for this payout attempt. This is usually temporary and does not mean your sats are lost. Your unpaid balance remains with OCEAN and we will retry after future OCEAN blocks. | |
| Action: | |
| No action is required yet. If this continues for more than 7 days, contact support with your mining address. | |
| Technical details: | |
| Raw CLN error: {rawError} | |
| CUSTODIAL_WALLET_ROUTE_UNAVAILABLE | |
| Title: | |
| Lightning payout delayed — wallet route unavailable | |
| Body: | |
| OCEAN could not find a working Lightning route to your wallet provider right now. You usually do not need to change anything. OCEAN will retry automatically after future OCEAN blocks. | |
| Action: | |
| If this continues for more than 7 days, try another supported BOLT12 wallet or contact support with your mining address. | |
| Technical details: | |
| Raw CLN error: {rawError} | |
| SELF_HOSTED_ROUTE_OR_LIQUIDITY | |
| Title: | |
| Lightning payout delayed — check your node’s incoming route | |
| Body: | |
| OCEAN could not find a usable route to your Lightning node. Having inbound liquidity helps, but your peers also need to be able to route the payout from OCEAN to you. | |
| Action: | |
| Check that your node is online, reachable, has enough inbound liquidity, and has well-connected public peers. OCEAN will retry automatically. | |
| Technical details: | |
| Raw CLN error: {rawError} | |
| RECIPIENT_UNREACHABLE | |
| Title: | |
| Lightning payout delayed — your node or offer is unreachable | |
| Body: | |
| OCEAN could not reach your Lightning node or BOLT12 offer to request the payout invoice. | |
| Action: | |
| Make sure your node is online, your BOLT12 offer is still active, your node is reachable over Tor if applicable, and your node is visible on Lightning gossip. Restarting your Lightning node may help. OCEAN will retry automatically. | |
| Technical details: | |
| Raw CLN error: {rawError} | |
| INVALID_BOLT12_OFFER | |
| Title: | |
| Lightning setup issue — update your BOLT12 offer | |
| Body: | |
| OCEAN could not use the BOLT12 offer configured for this mining address. | |
| Action: | |
| Create a new amountless BOLT12 offer, configure it on OCEAN, and sign it with the Bitcoin address used as your OCEAN username. Make sure the BOLT12 field contains an offer, not a Bitcoin address. | |
| Technical details: | |
| Raw CLN error: {rawError} | |
| KNOWN_CLN_PATH_TOO_LONG | |
| Title: | |
| Lightning payout delayed — known Core Lightning path issue | |
| Body: | |
| OCEAN could not build a valid payment path because the route was too long. Your unpaid balance is not lost. OCEAN will retry automatically, but this issue may require a different route or a backend fix. | |
| Action: | |
| If this continues for more than 48 hours, contact support with your mining address. | |
| Technical details: | |
| Raw CLN error: {rawError} | |
| UNKNOWN_BUT_RETRYING | |
| Title: | |
| Lightning payout delayed — OCEAN will retry automatically | |
| Body: | |
| The latest Lightning payout attempt failed, but your unpaid balance is not lost. OCEAN will retry automatically after future OCEAN blocks. | |
| Action: | |
| If this continues for more than 3 days, contact support with your mining address. | |
| Technical details: | |
| Raw CLN error: {rawError} | |
| 4. Add escalation logic. | |
| Create something like: | |
| shouldShowContactSupport(category, failedAttempts, ageHours) | |
| Rules: | |
| INVALID_BOLT12_OFFER: | |
| false by default; show setup instructions instead. | |
| KNOWN_CLN_PATH_TOO_LONG: | |
| show support CTA if failedAttempts >= 2 OR ageHours >= 48. | |
| RECIPIENT_UNREACHABLE: | |
| show support CTA if failedAttempts >= 3 OR ageHours >= 48. | |
| TEMPORARY_ROUTE_OR_LIQUIDITY: | |
| CUSTODIAL_WALLET_ROUTE_UNAVAILABLE: | |
| SELF_HOSTED_ROUTE_OR_LIQUIDITY: | |
| show support CTA if failedAttempts >= 6 OR ageHours >= 168. | |
| UNKNOWN_BUT_RETRYING: | |
| show support CTA if failedAttempts >= 3 OR ageHours >= 72. | |
| Before threshold, the UI should say: | |
| "No action required yet — OCEAN will retry automatically." | |
| After threshold, say: | |
| "If this continues, contact support with your mining address." | |
| 5. Improve the dashboard UI. | |
| Replace the current single error block with structured fields: | |
| Status: | |
| Lightning payout delayed | |
| Reason: | |
| Category-specific title/reason | |
| Action: | |
| Category-specific user action | |
| Retry info, if available: | |
| Last failed attempt: {timestamp} | |
| Failed attempts since last success: {count} | |
| Last successful Lightning payout: {timestamp or "none yet"} | |
| Next automatic retry: after the next eligible OCEAN block | |
| Technical details: | |
| Collapsed by default. | |
| Contains raw CLN error and raw code. | |
| 6. Preserve raw error visibility for debugging. | |
| Do not remove raw errors from backend/API logs. | |
| Do not hide them from advanced users entirely. | |
| Just make them collapsed/secondary in the dashboard. | |
| 7. Add tests. | |
| Add unit tests for the classifier with examples: | |
| - "cln err code: `205` - message `Failed: We could not find a usable set of paths...`" | |
| => TEMPORARY_ROUTE_OR_LIQUIDITY | |
| - "cln err code: `209` - message `Timed out after after 5 attempts. We got temporary_channel_failure...`" | |
| => TEMPORARY_ROUTE_OR_LIQUIDITY | |
| - "cln err code: `209` - message `Could not create payment onion: path too long!`" | |
| => KNOWN_CLN_PATH_TOO_LONG | |
| - "Latest lightning error: Node unreachable Raw error: cln err code: `1003`..." | |
| => RECIPIENT_UNREACHABLE | |
| - "cln err code: `1005` - Timeout waiting for response" | |
| => RECIPIENT_UNREACHABLE | |
| - "No route found Raw error: cln err code: `210`" | |
| => TEMPORARY_ROUTE_OR_LIQUIDITY | |
| - "offer rejected because amount field is present" | |
| => INVALID_BOLT12_OFFER | |
| - route error with context.walletType = "custodial" | |
| => CUSTODIAL_WALLET_ROUTE_UNAVAILABLE | |
| - route error with context.walletType = "self_hosted" | |
| => SELF_HOSTED_ROUTE_OR_LIQUIDITY | |
| 8. Add integration/snapshot tests for the dashboard copy. | |
| Verify: | |
| - Generic route failures no longer show "contact lightning@ocean.xyz". | |
| - Support CTA is hidden before threshold. | |
| - Support CTA appears after threshold. | |
| - Raw CLN error is still available under technical details. | |
| - Invalid BOLT12 offer shows setup instructions, not "wait." | |
| 9. Keep wording short and non-blaming. | |
| Avoid: | |
| "your wallet is broken" | |
| "OCEAN failed" | |
| "unknown error" | |
| "contact support" as the default | |
| Prefer: | |
| "Lightning payout delayed" | |
| "OCEAN will retry automatically" | |
| "Your unpaid balance is not lost" | |
| "No action required yet" | |
| "Check node reachability/liquidity" only when relevant | |
| Deliverables: | |
| - Classifier function and types. | |
| - Message mapping function. | |
| - Escalation function. | |
| - Dashboard UI update. | |
| - Unit tests and UI tests. | |
| - Remove/replace generic "Unknown payout error, contact lightning@ocean.xyz" for classified cases. |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment