{"record":{"id":"b9cc54510aaaea94","repo":"Billionmail/BillionMail","slug":"error-unmarshalling-site-map-v","errorCode":null,"errorMessage":"error unmarshalling site map: %v","messagePattern":"error unmarshalling site map: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"core/internal/service/askai/project.go","lineNumber":626,"sourceCode":"\t\temptySiteMapJson, err := json.MarshalIndent(emptySiteMap, \"\", \"  \")\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"error marshalling empty site map: %v\", err)\n\t\t}\n\t\terr = os.WriteFile(filename, emptySiteMapJson, 0644)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"error saving empty site map file: %v\", err)\n\t\t}\n\t\treturn emptySiteMap, nil\n\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.","sourceCodeStart":608,"sourceCodeEnd":644,"githubUrl":"https://github.com/Billionmail/BillionMail/blob/fc36c76c050c3775c5e899faf7403cf0262d2744/core/internal/service/askai/project.go#L608-L644","documentation":"After reading sitemap.json, GetSiteMap unmarshals it into []SiteMap with json.Unmarshal. This error means the file content is not a valid JSON array of SiteMap objects — corrupt, truncated, hand-edited, or of the wrong shape (e.g. a JSON object instead of an array).","triggerScenarios":"sitemap.json contains invalid JSON (interrupted write, manual edit with syntax errors), a JSON object instead of an array, or entries whose field types do not match SiteMap (e.g. a number where a string is expected).","commonSituations":"Concurrent writers corrupting the file (no locking between AddSiteMapNode/RemoveSiteMapNode/AppendSitemap); manual editing with a syntax mistake; restoring an old/partial backup; out-of-disk truncating the last write.","solutions":["Inspect sitemap.json with a JSON validator (jq . sitemap.json) to find the syntax/type problem and fix or remove the file.","If the file is unrepairable, delete it and let GetSiteMap bootstrap a fresh empty sitemap (after ensuring the write path is fixed).","Serialize writes with a file lock or a single-writer pattern to prevent concurrent corruption from AddSiteMapNode/RemoveSiteMapNode/AppendSitemap.","Consider writing atomically (write to a temp file, then os.Rename) so readers never see partial content."],"exampleFix":"// before\nerr = os.WriteFile(filename, data, 0644) // direct write: readers can see partial file\n// after\ntmp := filename + \".tmp\"\nif err := os.WriteFile(tmp, data, 0644); err != nil { return err }\nreturn os.Rename(tmp, filename) // atomic swap prevents corrupt reads","handlingStrategy":"validation","validationCode":"import \"encoding/json\"\n\nfunc sitemapFileValid(path string) bool {\n    data, err := os.ReadFile(path)\n    if err != nil { return false }\n    var m []SiteMap\n    return json.Unmarshal(data, &m) == nil\n}\n// if !sitemapFileValid(\".../sitemap.json\") { /* repair or delete before calling GetSiteMap */ }","typeGuard":null,"tryCatchPattern":"m, err := GetSiteMap(domain)\nif err != nil && strings.Contains(err.Error(), \"error unmarshalling site map\") {\n    log.Printf(\"corrupt sitemap for %s: %v\", domain, err)\n    os.Remove(filepath.Join(PRODUCT_CONFIG_PATH, domain, \"sitemap.json\"))\n    m, err = GetSiteMap(domain) // re-bootstrap a clean empty sitemap\n}","preventionTips":["Write sitemap.json atomically (temp file + os.Rename) so readers never see partial content.","Serialize all sitemap mutations (Add/Remove/Append) with a file lock or single-writer queue.","Validate sitemap.json after any manual edit or backup restore."],"tags":["go","json","corrupt-data","file-io"],"backgroundTag":"json-parse-error","analyzedSha":"fc36c76c050c3775c5e899faf7403cf0262d2744","analyzedAt":"2026-09-05T21:28:54.019Z","contentChangedAt":"2026-09-05T21:28:54.019Z","schemaVersion":2},"datasetVersion":"2026-09-12T22:17:10.623Z"}