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

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions