Billionmail/BillionMail · error
project configuration file does not exist
Error message
project configuration file does not exist: %s
What it means
ReadProjectConfig builds the path PRODUCT_CONFIG_PATH/<Domain>/project.json and requires it to exist before reading. If public.FileExists reports false, it returns this error naming the missing file, signaling the project was never initialized for that domain.
Solutions
- Run askai.Create(Domain, urls) first to generate the project.json for that domain
- Verify the exact Domain string matches the directory name under PRODUCT_CONFIG_PATH (case/spelling)
- Check the PRODUCT_CONFIG_PATH volume is mounted/persistent in deployment
- Handle the error by prompting the user to set up the project instead of failing the whole request
Example fix
// before
cfg, err := askai.ReadProjectConfig(domain)
if err != nil { return err }
// after
cfg, err := askai.ReadProjectConfig(domain)
if err != nil && strings.Contains(err.Error(), "does not exist") {
if err := askai.Create(domain, []string{"https://" + domain}); err != nil { return err }
cfg, err = askai.ReadProjectConfig(domain)
}
if err != nil { return err } Defensive patterns
Strategy: validation
Validate before calling
filename := filepath.Join(productConfigPath, domain, "project.json")
if _, err := os.Stat(filename); os.IsNotExist(err) {
// initialize first
if err := askai.Create(domain, []string{"https://" + domain}); err != nil { return err }
} Try / catch
cfg, err := askai.ReadProjectConfig(domain)
if err != nil {
if strings.Contains(err.Error(), "does not exist") {
return handleUninitializedProject(domain) // create or inform user
}
return err
} Prevention
- Always run Create before any Read/Set operations for a new domain
- Keep domain strings consistent (normalize case, strip slashes) between creation and lookup
- Mount PRODUCT_CONFIG_PATH as a persistent volume in deployments
- Add a setup check that lists existing project directories at startup
When it happens
Trigger: Any of GetProjectConfigPrompt, GetBaseInfo, GetProjectStatus, SetProjectStatus, ModifyBaseInfo, AutoGetProjectInfo calls ReadProjectConfig for a domain whose project.json was never created (Create not run), was deleted, or whose Domain string mismatches the on-disk directory (case, trailing slash, wrong domain).
Common situations: Fresh deployment where projects were never created; data volume not mounted so PRODUCT_CONFIG_PATH is empty; domain renamed/case-mismatch between DB and filesystem; manually cleaning the storage directory.
Understand the failure class
Background: "Config file not found": what it means and how to fix it in docker-sync, Maven, Vagrant, Turborepo and other tools — this error's family across 60 libraries.
Related errors
- error creating project configuration
- error reading prompt config file
- error saving default footer config file
- error saving default prompt config file
- error saving footer config file
AI-assisted analysis of Billionmail/BillionMail@fc36c76c05 (2026-09-05).
Data as JSON: /api/errors/f2a3073024b885e6.
Report an issue: GitHub.
Appendix: source
Thrown at core/internal/service/askai/project.go:106
type ImageInfo struct {
ImageId string `json:"image_id"` // 图片ID
ImageUrl string `json:"image_url"` // 图片URL
Filename string `json:"filename"` // 图片文件名
AltText string `json:"alt_text"` // 图片替代文本
ImageTag string `json:"image_tag"` // 图片标签
UpdateTime int64 `json:"update_time"` // 更新时间
Size string `json:"size"` // 图片大小 80x80
}
// 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.View on GitHub (pinned to fc36c76c05)