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

  1. Validate/pretty-print project.json with a JSON linter to find the syntax problem
  2. Restore the file by re-running Create/SaveProjectConfig or from backup
  3. Compare file fields against the current ProjectConfig struct after upgrades; migrate old schemas
  4. 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

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


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