From 69cea64ea050b9dee2967de570f0d436ecbc6ddb Mon Sep 17 00:00:00 2001 From: Rene Nochebuena Date: Sat, 21 Mar 2026 10:52:56 -0600 Subject: [PATCH] fix(httpserver): guard OnStop against nil srv when OnStart was never called If a component earlier in the launcher sequence fails during OnInit or OnStart, the launcher calls OnStop on every already-registered component for cleanup. httpserver.OnStop previously called s.srv.Shutdown(ctx) unconditionally; because s.srv is only assigned inside OnStart, any shutdown triggered before OnStart ran caused a nil pointer panic. Add an early return in OnStop: `if s.srv == nil { return nil }`. --- CHANGELOG.md | 9 +++++++++ httpserver.go | 6 +++++- 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 58ec349..4117548 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,14 @@ All notable changes to this module will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this module adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [0.9.1] - 2026-03-21 + +### Fixed + +- `OnStop` now returns `nil` immediately when `s.srv == nil`, preventing a nil pointer + panic when the launcher calls cleanup on a server component whose `OnStart` was never + reached (e.g. because an earlier component failed during startup). + ## [0.9.0] - 2026-03-18 ### Added @@ -25,4 +33,5 @@ and this module adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0. - No middleware is installed by default; the full middleware stack is composed explicitly via `WithMiddleware` at construction time, keeping the stack visible and ordering unambiguous in the application source - chi was chosen as the underlying router because it uses stdlib `http.Handler` throughout, making it fully compatible with `httpmw` middleware and `httputil` handler adapters without any wrapper code at the boundary +[0.9.1]: https://code.nochebuena.dev/go/httpserver/releases/tag/v0.9.1 [0.9.0]: https://code.nochebuena.dev/go/httpserver/releases/tag/v0.9.0 diff --git a/httpserver.go b/httpserver.go index af901af..dce277a 100644 --- a/httpserver.go +++ b/httpserver.go @@ -107,8 +107,12 @@ func (s *httpServer) OnStart() error { } // OnStop performs a graceful shutdown, waiting up to 10 seconds for in-flight -// requests to complete. +// requests to complete. If OnStart was never called (e.g. a prior component +// failed during startup), this is a no-op. func (s *httpServer) OnStop() error { + if s.srv == nil { + return nil + } s.logger.Info("httpserver: shutting down gracefully") ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) defer cancel()