Skip to content

log.Fatalf in HandleSignInvoiceRequest terminates process instead of returning error #183

@Ggwpnobe-dev

Description

@Ggwpnobe-dev

Summary

HandleSignInvoiceRequest in remotesigning/remote_signing.go:302 calls log.Fatalf() when SignInvoiceHash returns an error. Since log.Fatalf calls os.Exit(1), this immediately terminates the entire
process — the return nil, err on line 303 is dead code that never executes.

This is in the remotesigning library package, so any Go server that imports it and handles SIGN_INVOICE webhooks inherits an unrecoverable crash on signing errors.

Affected Code

https://github.com/lightsparkdev/go-sdk/blob/main/remotesigning/remote_signing.go#L302

signedInvoice, err := lightspark_crypto.SignInvoiceHash(seedBytes, bitcoinNetwork, hash)
if err != nil {
    log.Fatalf("Error signing invoice: %v", err)  // ← calls os.Exit(1)
    return nil, err                                 // ← dead code
}

Why This Is a Problem

  1. Library code should not call os.Exit. Package remotesigning is an importable library, not a main package. Callers cannot prevent or recover from os.Exit(1) — Go's recover() doesn't catch it and deferred
    cleanup functions don't run.
  2. Every other handler in the same file returns errors properly:
Function Error Handling
HandleEcdhRequest return nil, err
HandleGetPerCommitmentPointRequest return nil, err
HandleReleasePerCommitmentSecretRequest return nil, err
HandleDeriveKeyAndSignRequest return nil, err
HandleInvoicePaymentHashRequest return nil, err
HandleReleaseInvoicePreimageRequest return nil, err
HandleSignInvoiceRequest log.Fatalf → os.Exit(1)
  1. The Kotlin SDK handles the same case correctly with a recoverable exception:
    throw RemoteSigningException("Error signing invoice", cause = e)
  2. The reference server in examples/remote-signing-server/server.go calls this function via HandleRemoteSigningWebhook. A signing error crashes the entire server instead of returning a 500 response.

Suggested Fix

Replace log.Fatalf with a normal error return, matching all other handlers:

  signedInvoice, err := lightspark_crypto.SignInvoiceHash(seedBytes, bitcoinNetwork, hash)
  if err != nil {
      return nil, fmt.Errorf("error signing invoice: %w", err)
  }

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions