Billionmail/BillionMail · error

error unmarshalling site map: %v

Error message

error unmarshalling site map: %v

What it means

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).

Source

Thrown at core/internal/service/askai/project.go:626

		emptySiteMapJson, err := json.MarshalIndent(emptySiteMap, "", "  ")
		if err != nil {
			return nil, fmt.Errorf("error marshalling empty site map: %v", err)
		}
		err = os.WriteFile(filename, emptySiteMapJson, 0644)
		if err != nil {
			return nil, fmt.Errorf("error saving empty site map file: %v", err)
		}
		return emptySiteMap, nil
	}
	data, err := os.ReadFile(filename)
	if err != nil {
		return nil, fmt.Errorf("error reading site map file: %v", err)
	}

	var siteMap []SiteMap
	err = json.Unmarshal(data, &siteMap)
	if err != nil {
		return nil, fmt.Errorf("error unmarshalling site map: %v", err)
	}
	return siteMap, nil
}

func SaveSiteMap(Domain string, siteMap []SiteMap) error {
	filename := fmt.Sprintf(PRODUCT_CONFIG_PATH+"/%s/sitemap.json", Domain)
	data, err := json.MarshalIndent(siteMap, "", "  ")
	if err != nil {
		return fmt.Errorf("error marshalling site map: %v", err)
	}
	err = os.WriteFile(filename, data, 0644)
	if err != nil {
		return fmt.Errorf("error saving site map file: %v", err)
	}
	return nil
}

// AddSiteMapNode adds a new site map node with the provided title and URI path to the site map of the specified domain.

View on GitHub (pinned to fc36c76c05)

Solutions

  1. Inspect sitemap.json with a JSON validator (jq . sitemap.json) to find the syntax/type problem and fix or remove the file.
  2. If the file is unrepairable, delete it and let GetSiteMap bootstrap a fresh empty sitemap (after ensuring the write path is fixed).
  3. Serialize writes with a file lock or a single-writer pattern to prevent concurrent corruption from AddSiteMapNode/RemoveSiteMapNode/AppendSitemap.
  4. Consider writing atomically (write to a temp file, then os.Rename) so readers never see partial content.

Example fix

// before
err = os.WriteFile(filename, data, 0644) // direct write: readers can see partial file
// after
tmp := filename + ".tmp"
if err := os.WriteFile(tmp, data, 0644); err != nil { return err }
return os.Rename(tmp, filename) // atomic swap prevents corrupt reads
Defensive patterns

Strategy: validation

Validate before calling

import "encoding/json"

func sitemapFileValid(path string) bool {
    data, err := os.ReadFile(path)
    if err != nil { return false }
    var m []SiteMap
    return json.Unmarshal(data, &m) == nil
}
// if !sitemapFileValid(".../sitemap.json") { /* repair or delete before calling GetSiteMap */ }

Try / catch

m, err := GetSiteMap(domain)
if err != nil && strings.Contains(err.Error(), "error unmarshalling site map") {
    log.Printf("corrupt sitemap for %s: %v", domain, err)
    os.Remove(filepath.Join(PRODUCT_CONFIG_PATH, domain, "sitemap.json"))
    m, err = GetSiteMap(domain) // re-bootstrap a clean empty sitemap
}

Prevention

When it happens

Trigger: 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).

Common situations: 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.

Understand the failure class

Background: JSON parse error: "Unexpected token" / "not valid JSON" / "failed to parse" — what JSON parsers are really complaining about — this error's family across 45 libraries.

Related errors


AI-assisted analysis of Billionmail/BillionMail@fc36c76c05 (2026-09-05). Data as JSON: /api/errors/b9cc54510aaaea94. Report an issue: GitHub.