{"record":{"id":"f2a3073024b885e6","repo":"Billionmail/BillionMail","slug":"project-configuration-file-does-not-exist-s","errorCode":null,"errorMessage":"project configuration file does not exist: %s","messagePattern":"project configuration file does not exist: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"core/internal/service/askai/project.go","lineNumber":106,"sourceCode":"type ImageInfo struct {\n\tImageId    string `json:\"image_id\"`    // 图片ID\n\tImageUrl   string `json:\"image_url\"`   // 图片URL\n\tFilename   string `json:\"filename\"`    // 图片文件名\n\tAltText    string `json:\"alt_text\"`    // 图片替代文本\n\tImageTag   string `json:\"image_tag\"`   // 图片标签\n\tUpdateTime int64  `json:\"update_time\"` // 更新时间\n\tSize       string `json:\"size\"`        // 图片大小 80x80\n}\n\n// ReadProjectConfig reads the project configuration from a JSON file based on the provided domain.\n// It returns a ProjectConfig struct or an error if the file does not exist or cannot be read.\nfunc ReadProjectConfig(Domain string) (ProjectConfig, error) {\n\n\tfilename := fmt.Sprintf(PRODUCT_CONFIG_PATH+\"/%s/project.json\", Domain)\n\t// Here you would implement the logic to read the project configuration from the file.\n\t// For now, we will just return a placeholder string.\n\tif !public.FileExists(filename) {\n\t\treturn ProjectConfig{}, fmt.Errorf(\"project configuration file does not exist: %s\", filename)\n\t}\n\tdata, err := os.ReadFile(filename)\n\tif err != nil {\n\t\treturn ProjectConfig{}, fmt.Errorf(\"error reading project configuration file: %v\", err)\n\t}\n\n\tvar config ProjectConfig\n\terr = json.Unmarshal(data, &config)\n\tif err != nil {\n\t\treturn ProjectConfig{}, fmt.Errorf(\"error unmarshalling project configuration: %v\", err)\n\t}\n\treturn config, nil\n}\n\n// SaveProjectConfig saves the provided ProjectConfig to a JSON file based on the domain.\n// It creates the directory if it does not exist and writes the configuration to project.json.\n// If the file cannot be written, it returns an error.\n// If the directory does not exist, it creates it with appropriate permissions.","sourceCodeStart":88,"sourceCodeEnd":124,"githubUrl":"https://github.com/Billionmail/BillionMail/blob/fc36c76c050c3775c5e899faf7403cf0262d2744/core/internal/service/askai/project.go#L88-L124","documentation":"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.","triggerScenarios":"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).","commonSituations":"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.","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"],"exampleFix":"// before\ncfg, err := askai.ReadProjectConfig(domain)\nif err != nil { return err }\n// after\ncfg, err := askai.ReadProjectConfig(domain)\nif err != nil && strings.Contains(err.Error(), \"does not exist\") {\n    if err := askai.Create(domain, []string{\"https://\" + domain}); err != nil { return err }\n    cfg, err = askai.ReadProjectConfig(domain)\n}\nif err != nil { return err }","handlingStrategy":"validation","validationCode":"filename := filepath.Join(productConfigPath, domain, \"project.json\")\nif _, err := os.Stat(filename); os.IsNotExist(err) {\n    // initialize first\n    if err := askai.Create(domain, []string{\"https://\" + domain}); err != nil { return err }\n}","typeGuard":null,"tryCatchPattern":"cfg, err := askai.ReadProjectConfig(domain)\nif err != nil {\n    if strings.Contains(err.Error(), \"does not exist\") {\n        return handleUninitializedProject(domain) // create or inform user\n    }\n    return err\n}","preventionTips":["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"],"tags":["go","filesystem","config","project-setup"],"backgroundTag":"config-file-not-found","analyzedSha":"fc36c76c050c3775c5e899faf7403cf0262d2744","analyzedAt":"2026-09-05T21:28:54.019Z","contentChangedAt":"2026-09-05T21:28:54.019Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}