{"record":{"id":"8fba8e0a389c5049","repo":"Billionmail/BillionMail","slug":"error-marshalling-site-map-v","errorCode":null,"errorMessage":"error marshalling site map: %v","messagePattern":"error marshalling site map: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"core/internal/service/askai/project.go","lineNumber":635,"sourceCode":"\t}\n\tdata, err := os.ReadFile(filename)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"error reading site map file: %v\", err)\n\t}\n\n\tvar siteMap []SiteMap\n\terr = json.Unmarshal(data, &siteMap)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"error unmarshalling site map: %v\", err)\n\t}\n\treturn siteMap, nil\n}\n\nfunc SaveSiteMap(Domain string, siteMap []SiteMap) error {\n\tfilename := fmt.Sprintf(PRODUCT_CONFIG_PATH+\"/%s/sitemap.json\", Domain)\n\tdata, err := json.MarshalIndent(siteMap, \"\", \"  \")\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error marshalling site map: %v\", err)\n\t}\n\terr = os.WriteFile(filename, data, 0644)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error saving site map file: %v\", err)\n\t}\n\treturn nil\n}\n\n// AddSiteMapNode adds a new site map node with the provided title and URI path to the site map of the specified domain.\n// It reads the existing site map, appends the new node, and saves the updated site map back to the file.\n// If the site map file does not exist or cannot be read, it returns an error.\nfunc AddSiteMapNode(Domain string, Title string, UriPath string) error {\n\tsiteMap, err := GetSiteMap(Domain)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error getting site map: %v\", err)\n\t}\n\n\tnewNode := SiteMap{","sourceCodeStart":617,"sourceCodeEnd":653,"githubUrl":"https://github.com/Billionmail/BillionMail/blob/fc36c76c050c3775c5e899faf7403cf0262d2744/core/internal/service/askai/project.go#L617-L653","documentation":"SaveSiteMap marshals a []SiteMap with json.MarshalIndent before writing sitemap.json. This error wraps a marshalling failure. Like the other marshal errors here, it cannot fire with the current plain-struct SiteMap; it requires unmarshalable values (chan, func, cyclic pointers) in the slice.","triggerScenarios":"Calling SaveSiteMap (directly or via AppendSitemap) with a []SiteMap containing an element with an unsupported field type, or a slice built from a cyclic data structure.","commonSituations":"Encountered by developers extending SiteMap with non-JSON-serializable fields, or in tests injecting mocks with channels/functions into nodes.","solutions":["Read the wrapped message ('json: unsupported type: ...') to identify the offending SiteMap field.","Replace the unmarshalable field with a serializable equivalent (string key, plain struct, JSON tag adjustments).","Implement a custom json.Marshaler only if the field genuinely needs derived output, and guarantee it emits valid JSON."],"exampleFix":"// before\ntype SiteMap struct {\n    Loader func() error // unsupported by encoding/json\n}\n// after\ntype SiteMap struct {\n    LoaderName string // store an identifier instead of a func\n}","handlingStrategy":"validation","validationCode":"// Build-time sentinel: fails fast if SiteMap ever becomes unmarshalable\nvar _ = func() bool {\n    if _, err := json.Marshal([]SiteMap{{Title: \"t\", UriPath: \"/\"}}); err != nil {\n        panic(\"SiteMap not JSON-marshalable: \" + err.Error())\n    }\n    return true\n}()","typeGuard":"func isMarshalableSiteMap(m []SiteMap) bool {\n    _, err := json.Marshal(m)\n    return err == nil\n}","tryCatchPattern":"if err := SaveSiteMap(domain, siteMap); err != nil {\n    var ut *json.UnsupportedTypeError\n    if errors.As(err, &ut) { log.Printf(\"unmarshalable field %s\", ut.Type) }\n    return err\n}","preventionTips":["Restrict SiteMap fields to JSON-native types; no chan/func/sync members.","Add a CI test marshalling a fully populated []SiteMap.","Marshal inside SaveSiteMap before any side effects so failures are pure errors."],"tags":["go","json","serialization","sitemap"],"backgroundTag":"json-unsupported-type","analyzedSha":"fc36c76c050c3775c5e899faf7403cf0262d2744","analyzedAt":"2026-09-05T21:28:54.019Z","contentChangedAt":"2026-09-05T21:28:54.019Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}