diff --git a/server/internal/services/statussnapshot.go b/server/internal/services/statussnapshot.go index 857dd0b..f44903d 100644 --- a/server/internal/services/statussnapshot.go +++ b/server/internal/services/statussnapshot.go @@ -375,6 +375,21 @@ func componentStatus(mon models.Monitor, known, inMaintenance bool, now time.Tim const statusCacheTTL = 30 * time.Second +// unavailableSnapshot returns a StatusSnapshot with Available: false and all +// four list fields initialized to empty slices rather than nil, ensuring +// consistent JSON serialization across the available and unavailable paths. +func unavailableSnapshot(reason, title string) *StatusSnapshot { + return &StatusSnapshot{ + Available: false, + Reason: reason, + Title: title, + Sections: []PublicSection{}, + ActiveIncidents: []PublicIncident{}, + UpcomingMaintenance: []PublicIncident{}, + History: []PublicIncident{}, + } +} + // PublicStatusSnapshot is the whole public read path. // // A missing page, an unpublished page and a page belonging to another instance @@ -401,10 +416,10 @@ func PublicStatusSnapshot(instanceID, pageID string) (*StatusSnapshot, error) { // and deserves an explanation rather than a browser error. st := GetLicenseState(instanceID) if !st.Active() { - return &StatusSnapshot{Available: false, Reason: "licence_inactive", Title: page.Title}, nil + return unavailableSnapshot("licence_inactive", page.Title), nil } if !st.Feature(license.FeatureStatusPages) { - return &StatusSnapshot{Available: false, Reason: "feature_unavailable", Title: page.Title}, nil + return unavailableSnapshot("feature_unavailable", page.Title), nil } in, err := loadSnapshotInput(instanceID, *page)