Skip to content

fix: peer connect error handling and open channel button validation#3769

Open
myxmaster wants to merge 2 commits intoZeusLN:masterfrom
myxmaster:fix/open-channel-peer-connect-validation
Open

fix: peer connect error handling and open channel button validation#3769
myxmaster wants to merge 2 commits intoZeusLN:masterfrom
myxmaster:fix/open-channel-peer-connect-validation

Conversation

@myxmaster
Copy link
Copy Markdown
Collaborator

@myxmaster myxmaster commented Feb 28, 2026

Description

This fixes #3768.

Bug 1: Cryptic proto error when connecting peer by pubkey only

When connecting a peer without a host:port in "Connect Peer only" mode, an early-return code path in connectPeer() incorrectly set channelRequest, triggering a MobX reaction that called openChannel() instead of connectPeer(). This caused LND to receive an open-channel request with an empty local_funding_amount (uint64 in protobuf), producing the cryptic error proto: invalid value for uint64 type: "".

The early-return (intended for the "open channel, peer already known" path) now only applies when connectPeerOnly is false. The actual connectPeer backend call proceeds and LND handles gossip lookup, returning an error if the peer is not reachable.
-> I noticed that LND does not return a nice error message, but only "EOF", but this is something that has to be fixed on LND side. Until then I don't think we need a temporary workaround on Zeus side (meaning: display a user friendly error msg), because it is an edge case anyway; usually people will provide host:port.

Also fixed a resulting unhandled promise rejection in OpenChannel.tsx where connectPeer() was called without .catch().

Bug 2: "Open Channel" / "Connect Peer" button active although required fields are empty

Several validation state issues caused the Open Channel / Connect Peer button to remain active when required inputs were empty:

  • Switching from "Olympus by ZEUS" to "Custom" did not reset isNodePubkeyValid to false
  • Switching back to "Olympus by ZEUS" did not restore isNodePubkeyValid/isNodeHostValid to true
  • Switching back to "Olympus by ZEUS" did not restore isNodePubkeyValid to true; isNodeHostValid was refactored out of state entirely and is now derived from host in render, consistent with how isInvalidFeeRate is handled
  • AmountInput initializes by calling onAmountChange with satAmount = '0' (string), so !satAmount never triggered -> fixed by checking !Number(satAmount)
  • Disabling the "Use all possible funds" toggle did not reset satAmount in parent state, because AmountInput.componentDidUpdate does not call onAmountChange in its else-branch -> fixed by explicitly resetting satAmount: '0' in the toggle handler

This pull request is categorized as a:

  • New feature
  • Bug fix
  • Code refactor
  • Configuration change
  • Locales update
  • Quality assurance
  • Other

Checklist

  • I’ve run yarn run tsc and made sure my code compiles correctly
  • I’ve run yarn run lint and made sure my code didn’t contain any problematic patterns
  • I’ve run yarn run prettier and made sure my code is formatted correctly
  • I’ve run yarn run test and made sure all of the tests pass

Testing

If you modified or added a utility file, did you add new unit tests?

  • No, I’m a fool
  • Yes
  • N/A

I have tested this PR on the following platforms (please specify OS version and phone model/VM):

  • Android
  • iOS

I have tested this PR with the following types of nodes (please specify node version and API version where appropriate):

  • Embedded LND
  • LND (REST)
  • LND (Lightning Node Connect)
  • Core Lightning (CLNRest)
  • Nostr Wallet Connect
  • LndHub

Locales

  • I’ve added new locale text that requires translations
  • I’m aware that new translations should be made on the ZEUS Transfix page and not directly to this repo

Third Party Dependencies and Packages

  • Contributors will need to run yarn after this PR is merged in
  • 3rd party dependencies have been modified:
    • verify that package.json and yarn.lock have been properly updated
    • verify that dependencies are installed for both iOS and Android platforms

Other:

  • Changes were made that require an update to the README
  • Changes were made that require an update to onboarding

@gemini-code-assist
Copy link
Copy Markdown
Contributor

Summary of Changes

Hello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request addresses critical bugs related to peer connection and channel opening workflows. It refines the logic for connecting to peers, preventing an erroneous channel opening attempt when only a public key is provided. Additionally, it significantly improves the user experience by ensuring that the 'Open Channel' and 'Connect Peer' buttons accurately reflect the validity of user inputs, preventing submission with incomplete or invalid data.

Highlights

  • Peer Connection Error Handling: Corrected an issue where connecting a peer by pubkey only, without a host, would incorrectly trigger an open channel request instead of a peer connection, leading to a cryptic protobuf error. The connectPeer function now correctly handles connectPeerOnly mode, allowing LND to perform gossip lookup.
  • Unhandled Promise Rejection: Resolved an unhandled promise rejection in OpenChannel.tsx that occurred when connectPeer() was called without a .catch() block, improving application stability.
  • Open Channel/Connect Peer Button Validation: Fixed several validation issues that caused the 'Open Channel' / 'Connect Peer' button to remain active when required input fields were empty. This includes proper resetting of isNodePubkeyValid and isNodeHostValid when switching channel destinations, and ensuring satAmount is reset when the 'Use all possible funds' toggle is disabled.
Changelog
  • stores/ChannelsStore.ts
    • Modified the connectPeer function to correctly differentiate between connecting a peer only and opening a channel, preventing an incorrect early return when connectPeerOnly is true and no host is provided.
  • views/OpenChannel.tsx
    • Updated the onValueChange handler for channel destination selection to explicitly set isNodePubkeyValid and isNodeHostValid states, ensuring correct button validation when switching between 'Olympus by ZEUS' and 'Custom' destinations.
    • Added satAmount: '0' to the state update when the 'Use all possible funds' toggle is disabled, ensuring the amount input is reset and validation functions correctly.
    • Included a .catch(() => {}) block for the connectPeer() call to prevent unhandled promise rejections.
    • Enhanced the disabled condition for the 'Open Channel' / 'Connect Peer' button to include a check for a valid satAmount when not in connectPeerOnly mode and not using max funds, ensuring the button is disabled if the amount is zero or empty.
Activity
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request addresses two bugs: an error when connecting to a peer with only a public key, and incorrect validation logic for the 'Open Channel' button. The changes correctly fix these issues by adjusting the logic in connectPeer, adding proper state management for form inputs, and improving button validation. I've provided one comment highlighting a UX inconsistency related to host validation, emphasizing the importance of a smoother user experience as per our guidelines. Overall, the changes are solid and effectively resolve the reported problems.

Comment thread views/OpenChannel.tsx Outdated
@myxmaster myxmaster force-pushed the fix/open-channel-peer-connect-validation branch from 8eb0818 to 231ec59 Compare February 28, 2026 13:02
Comment thread views/OpenChannel.tsx Outdated
false,
connectPeerOnly
);
).catch(() => {});
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should we not display an error here if an error is thrown?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This catch is just a minimal fix to suppress the unhandled promise rejection. I think a clean solution belongs in a separate PR (see this issue as ToDo).

In short:
There is a deeper inconsistency, which needs to be fixed. connectPeer communicates errors through two channels simultaneously: MobX observables (for the UI) and reject() (for programmatic use), but openChannel only uses observables. No caller actually uses the rejection. So the clean solution would be to align both methods: always
resolve(true/false), never reject(), and let callers react to the boolean return value.

@myxmaster myxmaster force-pushed the fix/open-channel-peer-connect-validation branch from 231ec59 to 800cdae Compare March 31, 2026 10:03
@myxmaster
Copy link
Copy Markdown
Collaborator Author

(rebased)

@myxmaster myxmaster force-pushed the fix/open-channel-peer-connect-validation branch from 800cdae to 402b267 Compare April 1, 2026 11:43
@myxmaster
Copy link
Copy Markdown
Collaborator Author

(rebased)

Comment thread views/OpenChannel.tsx Outdated
@myxmaster myxmaster force-pushed the fix/open-channel-peer-connect-validation branch from 402b267 to ff8a051 Compare April 2, 2026 09:22
@myxmaster myxmaster requested a review from kaloudis April 2, 2026 09:25
@kaloudis kaloudis requested a review from ajaysehwal April 2, 2026 19:27
@kaloudis kaloudis added the Bug Something isn't working label Apr 2, 2026
@myxmaster myxmaster force-pushed the fix/open-channel-peer-connect-validation branch from ff8a051 to a5d3870 Compare April 5, 2026 09:16
@myxmaster
Copy link
Copy Markdown
Collaborator Author

(rebased)

Comment thread views/OpenChannel.tsx

const loading = connectingToPeer || openingChannel;

const isNodeHostValid =
Copy link
Copy Markdown
Contributor

@ajaysehwal ajaysehwal Apr 6, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@myxmaster, ValidationUtils.validateNodeHost returns false for empty strings, but isNodeHostValid ends up treating them as valid in isInvalidPeer. This logic seems incorrect. Could you please take another look?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

validateNodeHost deliberately returns false for empty strings because an empty string is not a valid host address format. However, providing a host is optional in this context here (LND and CLN both support connecting to a peer by pubkey only).
For this reason, isNodeHostValid is computed as host === '' || ValidationUtils.validateNodeHost(host) -> empty is valid in this view (gossip lookup will be attempted).

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

Labels

Bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 minor UI bugs: Open Channel / Connect Peer

3 participants