From 9047adff34b4e74093821b8ece1b166f1933ae9b Mon Sep 17 00:00:00 2001 From: Damilola Edwards Date: Wed, 19 Aug 2026 10:28:27 +0100 Subject: [PATCH] Fix Genesis() silently returning nil instead of an error Spec() and Genesis() are both cached values that may not be ready before bootstrap completes, but Spec() returned an error on unset while Genesis() returned a bare nil. A consumer checking the error the same way for both would nil deref on Genesis. Now both getters share the same contract. --- pkg/beacon/beacon.go | 4 ++++ pkg/beacon/beacon_test.go | 21 +++++++++++++++++++++ 2 files changed, 25 insertions(+) diff --git a/pkg/beacon/beacon.go b/pkg/beacon/beacon.go index 0b1eb83..c2fb182 100644 --- a/pkg/beacon/beacon.go +++ b/pkg/beacon/beacon.go @@ -372,6 +372,10 @@ func (n *node) Genesis() (*v1.Genesis, error) { n.genesisMu.RLock() defer n.genesisMu.RUnlock() + if n.genesis == nil { + return nil, errors.New("genesis is not available") + } + return n.genesis, nil } diff --git a/pkg/beacon/beacon_test.go b/pkg/beacon/beacon_test.go index e840886..eb988c6 100644 --- a/pkg/beacon/beacon_test.go +++ b/pkg/beacon/beacon_test.go @@ -123,3 +123,24 @@ func TestLifecycleStartStopSequence(t *testing.T) { t.Error("context was not cancelled after Stop") } } + +// TestGenesisErrorsWhenUnset matches Spec()'s behavior: both are cached +// values that may not be ready yet, and a consumer applying the same +// err-checking idiom to either one should get the same contract. +func TestGenesisErrorsWhenUnset(t *testing.T) { + n := &node{log: logrus.New()} + + _, err := n.Spec() + if err == nil { + t.Fatal("expected Spec() to error when unset") + } + + g, err := n.Genesis() + if err == nil { + t.Fatal("expected Genesis() to error when unset, matching Spec()") + } + + if g != nil { + t.Fatalf("expected a nil genesis alongside the error, got %v", g) + } +}