diff --git a/cmd/sentry/sentry/sentry.go b/cmd/sentry/sentry/sentry.go
index cf97b4a84189229575c6cffc11dfa1de6074973f..42b7cec977710dd1e248c1ae668ab5d5103c173a 100644
--- a/cmd/sentry/sentry/sentry.go
+++ b/cmd/sentry/sentry/sentry.go
@@ -178,28 +178,18 @@ func makeP2PServer(
 	protocol p2p.Protocol,
 ) (*p2p.Server, error) {
 	var urls []string
-	switch genesisHash {
-	case params.MainnetGenesisHash:
-		urls = params.MainnetBootnodes
-	case params.SepoliaGenesisHash:
-		urls = params.SepoliaBootnodes
-	case params.RopstenGenesisHash:
-		urls = params.RopstenBootnodes
-	case params.GoerliGenesisHash:
-		urls = params.GoerliBootnodes
-	case params.RinkebyGenesisHash:
-		urls = params.RinkebyBootnodes
-	case params.SokolGenesisHash:
-		urls = params.SokolBootnodes
-	case params.FermionGenesisHash:
-		urls = params.FermionBootnodes
-	case params.MumbaiGenesisHash:
-		urls = params.MumbaiBootnodes
-	case params.BorMainnetGenesisHash:
-		urls = params.BorMainnetBootnodes
+	chainConfig := params.ChainConfigByGenesisHash(genesisHash)
+	if chainConfig != nil {
+		urls = params.BootnodeURLsOfChain(chainConfig.ChainName)
 	}
-	p2pConfig.BootstrapNodes, _ = utils.GetUrlListNodes(urls, utils.BootnodesFlag.Name, log.Crit)
-	p2pConfig.BootstrapNodesV5 = p2pConfig.BootstrapNodes
+
+	bootstrapNodes, err := utils.ParseNodesFromURLs(urls)
+	if err != nil {
+		return nil, fmt.Errorf("bad option %s: %w", utils.BootnodesFlag.Name, err)
+	}
+	p2pConfig.BootstrapNodes = bootstrapNodes
+	p2pConfig.BootstrapNodesV5 = bootstrapNodes
+
 	p2pConfig.Protocols = []p2p.Protocol{protocol}
 	return &p2p.Server{Config: p2pConfig}, nil
 }
diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go
index b024b2342e8d1b4cd0aa221cec4ca3f1458ca3f7..1527c2102812abcc8bdecb109951e3ecd393ca10 100644
--- a/cmd/utils/flags.go
+++ b/cmd/utils/flags.go
@@ -691,94 +691,45 @@ func setNodeUserIdentCobra(f *pflag.FlagSet, cfg *node.Config) {
 	}
 }
 
-// setBootstrapNodes creates a list of bootstrap nodes from the command line
-// flags, reverting to pre-configured ones if none have been specified.
 func setBootstrapNodes(ctx *cli.Context, cfg *p2p.Config) {
-	var urls []string
-	if ctx.GlobalIsSet(BootnodesFlag.Name) {
-		urls = SplitAndTrim(ctx.GlobalString(BootnodesFlag.Name))
-	} else {
-		chain := ctx.GlobalString(ChainFlag.Name)
-		switch chain {
-		case networkname.MainnetChainName:
-			urls = params.MainnetBootnodes
-		case networkname.SepoliaChainName:
-			urls = params.SepoliaBootnodes
-		case networkname.RopstenChainName:
-			urls = params.RopstenBootnodes
-		case networkname.RinkebyChainName:
-			urls = params.RinkebyBootnodes
-		case networkname.GoerliChainName:
-			urls = params.GoerliBootnodes
-		case networkname.BSCChainName:
-			urls = params.BscBootnodes
-		case networkname.ChapelChainName:
-			urls = params.ChapelBootnodes
-		case networkname.RialtoChainName:
-			urls = params.RialtoBootnodes
-		case networkname.ErigonMineName:
-			urls = params.ErigonBootnodes
-		case networkname.SokolChainName:
-			urls = params.SokolBootnodes
-		case networkname.FermionChainName:
-			urls = params.FermionBootnodes
-		case networkname.MumbaiChainName:
-			urls = params.MumbaiBootnodes
-		case networkname.BorMainnetChainName:
-			urls = params.BorMainnetBootnodes
-		default:
-			if cfg.BootstrapNodes != nil {
-				return // already set, don't apply defaults.
-			}
-		}
+	// If already set, don't apply defaults.
+	if cfg.BootstrapNodes != nil {
+		return
 	}
 
-	cfg.BootstrapNodes, _ = GetUrlListNodes(urls, BootnodesFlag.Name, log.Crit)
+	nodes, err := GetBootnodesFromFlags(ctx.GlobalString(BootnodesFlag.Name), ctx.GlobalString(ChainFlag.Name))
+	if err != nil {
+		Fatalf("Option %s: %v", BootnodesFlag.Name, err)
+	}
+
+	cfg.BootstrapNodes = nodes
 }
 
-// setBootstrapNodesV5 creates a list of bootstrap nodes from the command line
-// flags, reverting to pre-configured ones if none have been specified.
 func setBootstrapNodesV5(ctx *cli.Context, cfg *p2p.Config) {
+	// If already set, don't apply defaults.
+	if cfg.BootstrapNodesV5 != nil {
+		return
+	}
+
+	nodes, err := GetBootnodesFromFlags(ctx.GlobalString(BootnodesFlag.Name), ctx.GlobalString(ChainFlag.Name))
+	if err != nil {
+		Fatalf("Option %s: %v", BootnodesFlag.Name, err)
+	}
+
+	cfg.BootstrapNodesV5 = nodes
+}
+
+// GetBootnodesFromFlags makes a list of bootnodes from command line flags.
+// If urlsStr is given, it is used and parsed as a comma-separated list of enode:// urls,
+// otherwise a list of preconfigured bootnodes of the specified chain is returned.
+func GetBootnodesFromFlags(urlsStr, chain string) ([]*enode.Node, error) {
 	var urls []string
-	if ctx.GlobalIsSet(BootnodesFlag.Name) {
-		urls = SplitAndTrim(ctx.GlobalString(BootnodesFlag.Name))
+	if urlsStr != "" {
+		urls = SplitAndTrim(urlsStr)
 	} else {
-		chain := ctx.GlobalString(ChainFlag.Name)
-		switch chain {
-		case networkname.MainnetChainName:
-			urls = params.MainnetBootnodes
-		case networkname.SepoliaChainName:
-			urls = params.SepoliaBootnodes
-		case networkname.RopstenChainName:
-			urls = params.RopstenBootnodes
-		case networkname.RinkebyChainName:
-			urls = params.RinkebyBootnodes
-		case networkname.GoerliChainName:
-			urls = params.GoerliBootnodes
-		case networkname.BSCChainName:
-			urls = params.BscBootnodes
-		case networkname.ChapelChainName:
-			urls = params.ChapelBootnodes
-		case networkname.RialtoChainName:
-			urls = params.RialtoBootnodes
-		case networkname.ErigonMineName:
-			urls = params.ErigonBootnodes
-		case networkname.SokolChainName:
-			urls = params.SokolBootnodes
-		case networkname.FermionChainName:
-			urls = params.FermionBootnodes
-		case networkname.MumbaiChainName:
-			urls = params.MumbaiBootnodes
-		case networkname.BorMainnetChainName:
-			urls = params.BorMainnetBootnodes
-		default:
-			if cfg.BootstrapNodesV5 != nil {
-				return // already set, don't apply defaults.
-			}
-		}
+		urls = params.BootnodeURLsOfChain(chain)
 	}
-
-	cfg.BootstrapNodesV5, _ = GetUrlListNodes(urls, BootnodesFlag.Name, log.Error)
+	return ParseNodesFromURLs(urls)
 }
 
 func setStaticPeers(ctx *cli.Context, cfg *p2p.Config) {
@@ -787,52 +738,44 @@ func setStaticPeers(ctx *cli.Context, cfg *p2p.Config) {
 		urls = SplitAndTrim(ctx.GlobalString(StaticPeersFlag.Name))
 	} else {
 		chain := ctx.GlobalString(ChainFlag.Name)
-		switch chain {
-		case networkname.BSCChainName:
-			urls = params.BscStaticPeers
-		case networkname.ChapelChainName:
-			urls = params.ChapelStaticPeers
-		case networkname.RialtoChainName:
-			urls = params.RialtoStaticPeers
-		}
+		urls = params.StaticPeerURLsOfChain(chain)
+	}
+
+	nodes, err := ParseNodesFromURLs(urls)
+	if err != nil {
+		Fatalf("Option %s: %v", StaticPeersFlag.Name, err)
 	}
-	cfg.StaticNodes, _ = GetUrlListNodes(urls, StaticPeersFlag.Name, log.Error)
+
+	cfg.StaticNodes = nodes
 }
 
 func setTrustedPeers(ctx *cli.Context, cfg *p2p.Config) {
-	cfg.TrustedNodes, _ = appendCfgUrlListNodes(cfg.TrustedNodes, ctx, TrustedPeersFlag.Name, log.Error)
-}
+	if !ctx.GlobalIsSet(TrustedPeersFlag.Name) {
+		return
+	}
 
-func appendCfgUrlListNodes(nodes []*enode.Node, ctx *cli.Context, flagName string, logFn func(msg string, ctx ...interface{})) ([]*enode.Node, error) {
-	if ctx.GlobalIsSet(flagName) {
-		urls := SplitAndTrim(ctx.GlobalString(flagName))
-		return appendUrlListNodes(nodes, urls, flagName, logFn)
+	urls := SplitAndTrim(ctx.GlobalString(TrustedPeersFlag.Name))
+	trustedNodes, err := ParseNodesFromURLs(urls)
+	if err != nil {
+		Fatalf("Option %s: %v", TrustedPeersFlag.Name, err)
 	}
-	return nodes, nil
-}
 
-func GetUrlListNodes(urls []string, nodeType string, logFn func(msg string, ctx ...interface{})) (_ []*enode.Node, retErr error) {
-	return appendUrlListNodes(nil, urls, nodeType, logFn)
+	cfg.TrustedNodes = append(cfg.TrustedNodes, trustedNodes...)
 }
 
-func appendUrlListNodes(nodes []*enode.Node, urls []string, nodeType string, logFn func(msg string, ctx ...interface{})) (_ []*enode.Node, retErr error) {
-	if nodes == nil {
-		nodes = make([]*enode.Node, 0, len(urls))
-	}
+func ParseNodesFromURLs(urls []string) ([]*enode.Node, error) {
+	nodes := make([]*enode.Node, 0, len(urls))
 	for _, url := range urls {
-		if url != "" {
-			node, err := enode.Parse(enode.ValidSchemes, url)
-			if err != nil {
-				retErr = err
-				if logFn != nil {
-					logFn(fmt.Sprintf("%s URL invalid", nodeType), "url", url, "err", err)
-				}
-			} else {
-				nodes = append(nodes, node)
-			}
+		if url == "" {
+			continue
 		}
+		n, err := enode.Parse(enode.ValidSchemes, url)
+		if err != nil {
+			return nil, fmt.Errorf("invalid node URL %s: %w", url, err)
+		}
+		nodes = append(nodes, n)
 	}
-	return nodes, retErr
+	return nodes, nil
 }
 
 // NewP2PConfig
@@ -866,16 +809,16 @@ func NewP2PConfig(nodiscover bool, datadir, netRestrict, natSetting, nodeName st
 		cfg.NetRestrict.Add(netRestrict)
 	}
 	if staticPeers != nil {
-		staticNodes, err := GetUrlListNodes(staticPeers, StaticPeersFlag.Name, log.Error)
+		staticNodes, err := ParseNodesFromURLs(staticPeers)
 		if err != nil {
-			return nil, err
+			return nil, fmt.Errorf("bad option %s: %w", StaticPeersFlag.Name, err)
 		}
 		cfg.StaticNodes = staticNodes
 	}
 	if trustedPeers != nil {
-		trustedNodes, err := GetUrlListNodes(trustedPeers, TrustedPeersFlag.Name, log.Error)
+		trustedNodes, err := ParseNodesFromURLs(trustedPeers)
 		if err != nil {
-			return nil, err
+			return nil, fmt.Errorf("bad option %s: %w", TrustedPeersFlag.Name, err)
 		}
 		cfg.TrustedNodes = trustedNodes
 	}
diff --git a/core/genesis.go b/core/genesis.go
index 41f28065aafe2a30d61273d0d196e653467e50cc..7e88bb91c401f4ffb127d17adfa62248542b536f 100644
--- a/core/genesis.go
+++ b/core/genesis.go
@@ -277,37 +277,15 @@ func WriteGenesisBlock(db kv.RwTx, genesis *Genesis) (*params.ChainConfig, *type
 	return newcfg, storedBlock, nil
 }
 
-func (g *Genesis) configOrDefault(ghash common.Hash) *params.ChainConfig {
-	switch {
-	case g != nil:
+func (g *Genesis) configOrDefault(genesisHash common.Hash) *params.ChainConfig {
+	if g != nil {
 		return g.Config
-	case ghash == params.MainnetGenesisHash:
-		return params.MainnetChainConfig
-	case ghash == params.SepoliaGenesisHash:
-		return params.SepoliaChainConfig
-	case ghash == params.RopstenGenesisHash:
-		return params.RopstenChainConfig
-	case ghash == params.RinkebyGenesisHash:
-		return params.RinkebyChainConfig
-	case ghash == params.GoerliGenesisHash:
-		return params.GoerliChainConfig
-	case ghash == params.BSCGenesisHash:
-		return params.BSCChainConfig
-	case ghash == params.ChapelGenesisHash:
-		return params.ChapelChainConfig
-	case ghash == params.RialtoGenesisHash:
-		return params.RialtoChainConfig
-	case ghash == params.ErigonGenesisHash:
-		return params.ErigonChainConfig
-	case ghash == params.SokolGenesisHash:
-		return params.SokolChainConfig
-	case ghash == params.FermionGenesisHash:
-		return params.FermionChainConfig
-	case ghash == params.MumbaiGenesisHash:
-		return params.MumbaiChainConfig
-	case ghash == params.BorMainnetGenesisHash:
-		return params.BorMainnetChainConfig
-	default:
+	}
+
+	config := params.ChainConfigByGenesisHash(genesisHash)
+	if config != nil {
+		return config
+	} else {
 		return params.AllEthashProtocolChanges
 	}
 }
diff --git a/params/bootnodes.go b/params/bootnodes.go
index 0c5adc11ee6a6b91235cb8705683458c50daf37d..336207a17b51d5a44215f43a818ad4b1144feca8 100644
--- a/params/bootnodes.go
+++ b/params/bootnodes.go
@@ -16,7 +16,10 @@
 
 package params
 
-import "github.com/ledgerwatch/erigon/common"
+import (
+	"github.com/ledgerwatch/erigon/common"
+	"github.com/ledgerwatch/erigon/params/networkname"
+)
 
 // MainnetBootnodes are the enode URLs of the P2P bootstrap nodes running on
 // the main Ethereum network.
@@ -178,3 +181,49 @@ func KnownDNSNetwork(genesis common.Hash, protocol string) string {
 	}
 	return dnsPrefix + protocol + "." + net + ".ethdisco.net"
 }
+
+func BootnodeURLsOfChain(chain string) []string {
+	switch chain {
+	case networkname.MainnetChainName:
+		return MainnetBootnodes
+	case networkname.SepoliaChainName:
+		return SepoliaBootnodes
+	case networkname.RopstenChainName:
+		return RopstenBootnodes
+	case networkname.RinkebyChainName:
+		return RinkebyBootnodes
+	case networkname.GoerliChainName:
+		return GoerliBootnodes
+	case networkname.BSCChainName:
+		return BscBootnodes
+	case networkname.ChapelChainName:
+		return ChapelBootnodes
+	case networkname.RialtoChainName:
+		return RialtoBootnodes
+	case networkname.ErigonMineName:
+		return ErigonBootnodes
+	case networkname.SokolChainName:
+		return SokolBootnodes
+	case networkname.FermionChainName:
+		return FermionBootnodes
+	case networkname.MumbaiChainName:
+		return MumbaiBootnodes
+	case networkname.BorMainnetChainName:
+		return BorMainnetBootnodes
+	default:
+		return []string{}
+	}
+}
+
+func StaticPeerURLsOfChain(chain string) []string {
+	switch chain {
+	case networkname.BSCChainName:
+		return BscStaticPeers
+	case networkname.ChapelChainName:
+		return ChapelStaticPeers
+	case networkname.RialtoChainName:
+		return RialtoStaticPeers
+	default:
+		return []string{}
+	}
+}
diff --git a/params/config.go b/params/config.go
index c76a1c8cfe0eafaf1fb09d1c2b6e6868531379f9..853b9b2eb507f7b543ebc5a71461ae29bdd369ea 100644
--- a/params/config.go
+++ b/params/config.go
@@ -1097,3 +1097,36 @@ func (c *ChainConfig) Rules(num uint64) Rules {
 		IsParlia:         c.Parlia != nil,
 	}
 }
+
+func ChainConfigByGenesisHash(genesisHash common.Hash) *ChainConfig {
+	switch {
+	case genesisHash == MainnetGenesisHash:
+		return MainnetChainConfig
+	case genesisHash == SepoliaGenesisHash:
+		return SepoliaChainConfig
+	case genesisHash == RopstenGenesisHash:
+		return RopstenChainConfig
+	case genesisHash == RinkebyGenesisHash:
+		return RinkebyChainConfig
+	case genesisHash == GoerliGenesisHash:
+		return GoerliChainConfig
+	case genesisHash == BSCGenesisHash:
+		return BSCChainConfig
+	case genesisHash == ChapelGenesisHash:
+		return ChapelChainConfig
+	case genesisHash == RialtoGenesisHash:
+		return RialtoChainConfig
+	case genesisHash == ErigonGenesisHash:
+		return ErigonChainConfig
+	case genesisHash == SokolGenesisHash:
+		return SokolChainConfig
+	case genesisHash == FermionGenesisHash:
+		return FermionChainConfig
+	case genesisHash == MumbaiGenesisHash:
+		return MumbaiChainConfig
+	case genesisHash == BorMainnetGenesisHash:
+		return BorMainnetChainConfig
+	default:
+		return nil
+	}
+}