Billionmail/BillionMail · error
error unmarshalling project configuration: %v
Error message
error unmarshalling project configuration: %v
What it means
The file bytes read from project.json are decoded into ProjectConfig with json.Unmarshal; if the JSON does not match the struct (corrupt file, invalid JSON, renamed fields), the failure is wrapped as this error.
Source
Thrown at core/internal/service/askai/project.go:116
// ReadProjectConfig reads the project configuration from a JSON file based on the provided domain.
// It returns a ProjectConfig struct or an error if the file does not exist or cannot be read.
func ReadProjectConfig(Domain string) (ProjectConfig, error) {
filename := fmt.Sprintf(PRODUCT_CONFIG_PATH+"/%s/project.json", Domain)
// Here you would implement the logic to read the project configuration from the file.
// For now, we will just return a placeholder string.
if !public.FileExists(filename) {
return ProjectConfig{}, fmt.Errorf("project configuration file does not exist: %s", filename)
}
data, err := os.ReadFile(filename)
if err != nil {
return ProjectConfig{}, fmt.Errorf("error reading project configuration file: %v", err)
}
var config ProjectConfig
err = json.Unmarshal(data, &config)
if err != nil {
return ProjectConfig{}, fmt.Errorf("error unmarshalling project configuration: %v", err)
}
return config, nil
}
// SaveProjectConfig saves the provided ProjectConfig to a JSON file based on the domain.
// It creates the directory if it does not exist and writes the configuration to project.json.
// If the file cannot be written, it returns an error.
// If the directory does not exist, it creates it with appropriate permissions.
func SaveProjectConfig(Domain string, config ProjectConfig) error {
projectConfigPath := fmt.Sprintf("%s/%s", PRODUCT_CONFIG_PATH, Domain)
if !public.FileExists(projectConfigPath) {
os.MkdirAll(projectConfigPath, os.ModePerm)
}
filename := fmt.Sprintf("%s/project.json", projectConfigPath)
configStr, err := json.MarshalIndent(config, "", " ")
if err != nil {
return fmt.Errorf("error marshalling project configuration: %v", err)View on GitHub (pinned to fc36c76c05)
Solutions
- Validate/pretty-print project.json with a JSON linter to find the syntax problem
- Restore the file by re-running Create/SaveProjectConfig or from backup
- Compare file fields against the current ProjectConfig struct after upgrades; migrate old schemas
- Harden SaveProjectConfig to write to a temp file and atomically rename to avoid truncation
Example fix
// before
if err := json.Unmarshal(data, &config); err != nil {
return ProjectConfig{}, fmt.Errorf("error unmarshalling project configuration: %v", err)
}
// after
if err := json.Unmarshal(data, &config); err != nil {
// fall back to defaults so callers can re-init
return ProjectConfig{}, fmt.Errorf("error unmarshalling project configuration: %v", err)
}
// caller:
if strings.Contains(err.Error(), "unmarshalling") { os.Remove(filename); askai.Create(domain, urls) } Defensive patterns
Strategy: validation
Validate before calling
data, _ := os.ReadFile(filename)
if !json.Valid(data) {
return fmt.Errorf("%s contains invalid JSON; re-create the project config", filename)
} Type guard
func isValidProjectConfig(data []byte) bool {
var probe askai.ProjectConfig
return json.Unmarshal(data, &probe) == nil
} Try / catch
cfg, err := askai.ReadProjectConfig(domain)
if err != nil && strings.Contains(err.Error(), "unmarshalling") {
os.Remove(filename) // quarantine corrupt file
return reinitializeProject(domain)
} Prevention
- Make SaveProjectConfig write to a temp file then os.Rename for atomicity
- Never hand-edit project.json without validating with a JSON parser afterwards
- Run schema migrations when ProjectConfig struct fields change across versions
- Back up the config directory before upgrades
When it happens
Trigger: project.json contains invalid JSON (truncated write, manual edit), or fields whose types conflict with ProjectConfig (e.g. KnowledgeBase as object instead of array, Status as string instead of bool).
Common situations: A previous crash/power loss during os.WriteFile left a truncated file; hand-edited config with syntax errors; ProjectConfig struct fields renamed after a version upgrade while old files persist on disk.
Understand the failure class
Background: "failed to unmarshal" / json.Unmarshal errors: why parsing a response into a Go struct fails and how to fix it — this error's family across 23 libraries.
Related errors
- error marshalling project configuration: %v
- error unmarshalling footer config: %v
- error marshalling footer config: %v
- error marshalling default prompt config: %v
- error unmarshalling prompt config: %v
AI-assisted analysis of Billionmail/BillionMail@fc36c76c05 (2026-09-05).
Data as JSON: /api/errors/e9bf609d265f9848.
Report an issue: GitHub.