ScuttleBot

fix: nil pointer panic in topology handlers when topology not configured Add nil guards for s.topoMgr in all three topology API handlers. The topology manager is nil when no topology config is present, which caused a panic on GET /v1/topology (hit by the channels tab).

lmata 2026-04-03 19:23 trunk
Commit 319a0fe1b5aed88db74f271e6cf42d0e93e8a32653b008c1cd8299d47ff6a45f
--- internal/api/channels_topology.go
+++ internal/api/channels_topology.go
@@ -41,10 +41,14 @@
4141
}
4242
if err := topology.ValidateName(req.Name); err != nil {
4343
writeError(w, http.StatusBadRequest, err.Error())
4444
return
4545
}
46
+ if s.topoMgr == nil {
47
+ writeError(w, http.StatusServiceUnavailable, "topology not configured")
48
+ return
49
+ }
4650
4751
policy := s.topoMgr.Policy()
4852
4953
// Merge autojoin from policy if the caller didn't specify any.
5054
autojoin := req.Autojoin
@@ -95,18 +99,26 @@
9599
func (s *Server) handleDropChannel(w http.ResponseWriter, r *http.Request) {
96100
channel := "#" + r.PathValue("channel")
97101
if err := topology.ValidateName(channel); err != nil {
98102
writeError(w, http.StatusBadRequest, err.Error())
99103
return
104
+ }
105
+ if s.topoMgr == nil {
106
+ writeError(w, http.StatusServiceUnavailable, "topology not configured")
107
+ return
100108
}
101109
s.topoMgr.DropChannel(channel)
102110
w.WriteHeader(http.StatusNoContent)
103111
}
104112
105113
// handleGetTopology handles GET /v1/topology.
106114
// Returns the channel type rules and static channel names declared in config.
107115
func (s *Server) handleGetTopology(w http.ResponseWriter, r *http.Request) {
116
+ if s.topoMgr == nil {
117
+ writeJSON(w, http.StatusOK, topologyResponse{})
118
+ return
119
+ }
108120
policy := s.topoMgr.Policy()
109121
if policy == nil {
110122
writeJSON(w, http.StatusOK, topologyResponse{})
111123
return
112124
}
113125
--- internal/api/channels_topology.go
+++ internal/api/channels_topology.go
@@ -41,10 +41,14 @@
41 }
42 if err := topology.ValidateName(req.Name); err != nil {
43 writeError(w, http.StatusBadRequest, err.Error())
44 return
45 }
 
 
 
 
46
47 policy := s.topoMgr.Policy()
48
49 // Merge autojoin from policy if the caller didn't specify any.
50 autojoin := req.Autojoin
@@ -95,18 +99,26 @@
95 func (s *Server) handleDropChannel(w http.ResponseWriter, r *http.Request) {
96 channel := "#" + r.PathValue("channel")
97 if err := topology.ValidateName(channel); err != nil {
98 writeError(w, http.StatusBadRequest, err.Error())
99 return
 
 
 
 
100 }
101 s.topoMgr.DropChannel(channel)
102 w.WriteHeader(http.StatusNoContent)
103 }
104
105 // handleGetTopology handles GET /v1/topology.
106 // Returns the channel type rules and static channel names declared in config.
107 func (s *Server) handleGetTopology(w http.ResponseWriter, r *http.Request) {
 
 
 
 
108 policy := s.topoMgr.Policy()
109 if policy == nil {
110 writeJSON(w, http.StatusOK, topologyResponse{})
111 return
112 }
113
--- internal/api/channels_topology.go
+++ internal/api/channels_topology.go
@@ -41,10 +41,14 @@
41 }
42 if err := topology.ValidateName(req.Name); err != nil {
43 writeError(w, http.StatusBadRequest, err.Error())
44 return
45 }
46 if s.topoMgr == nil {
47 writeError(w, http.StatusServiceUnavailable, "topology not configured")
48 return
49 }
50
51 policy := s.topoMgr.Policy()
52
53 // Merge autojoin from policy if the caller didn't specify any.
54 autojoin := req.Autojoin
@@ -95,18 +99,26 @@
99 func (s *Server) handleDropChannel(w http.ResponseWriter, r *http.Request) {
100 channel := "#" + r.PathValue("channel")
101 if err := topology.ValidateName(channel); err != nil {
102 writeError(w, http.StatusBadRequest, err.Error())
103 return
104 }
105 if s.topoMgr == nil {
106 writeError(w, http.StatusServiceUnavailable, "topology not configured")
107 return
108 }
109 s.topoMgr.DropChannel(channel)
110 w.WriteHeader(http.StatusNoContent)
111 }
112
113 // handleGetTopology handles GET /v1/topology.
114 // Returns the channel type rules and static channel names declared in config.
115 func (s *Server) handleGetTopology(w http.ResponseWriter, r *http.Request) {
116 if s.topoMgr == nil {
117 writeJSON(w, http.StatusOK, topologyResponse{})
118 return
119 }
120 policy := s.topoMgr.Policy()
121 if policy == nil {
122 writeJSON(w, http.StatusOK, topologyResponse{})
123 return
124 }
125

Keyboard Shortcuts

Open search /
Next entry (timeline) j
Previous entry (timeline) k
Open focused entry Enter
Show this help ?
Toggle theme Top nav button