{"record":{"id":"14ce2b2c533af98e","repo":"Billionmail/BillionMail","slug":"error-reading-company-profile-file-v","errorCode":null,"errorMessage":"error reading company profile file: %v","messagePattern":"error reading company profile file: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"core/internal/service/askai/project.go","lineNumber":448,"sourceCode":"\t\t// If the company profile file does not exist, return a default profile\n\t\t// This allows the system to handle cases where the profile has not been set up yet\n\t\t// and avoids errors when trying to read a non-existent file.\n\t\t// It also allows the user to create a new profile without needing to handle file not\n\t\t// found errors.\n\t\tcompanyProfileDefault.UpdateTime = public.GetNowTime()\n\t\tcompanyProfileJson, err := json.MarshalIndent(companyProfileDefault, \"\", \"  \")\n\t\tif err != nil {\n\t\t\treturn CompanyProfile{}, fmt.Errorf(\"error marshalling company profile: %v\", err)\n\t\t}\n\t\terr = os.WriteFile(filename, companyProfileJson, 0644)\n\t\tif err != nil {\n\t\t\treturn CompanyProfile{}, fmt.Errorf(\"error creating company profile file: %v\", err)\n\t\t}\n\t\treturn companyProfileDefault, nil\n\t}\n\tdata, err := os.ReadFile(filename)\n\tif err != nil {\n\t\treturn CompanyProfile{}, fmt.Errorf(\"error reading company profile file: %v\", err)\n\t}\n\tvar profile CompanyProfile\n\terr = json.Unmarshal(data, &profile)\n\tif err != nil {\n\t\treturn CompanyProfile{}, fmt.Errorf(\"error unmarshalling company profile: %v\", err)\n\t}\n\treturn profile, nil\n}\n\n// SaveCompanyProfile saves the provided CompanyProfile to a JSON file based on the domain.\n// It creates the directory if it does not exist and writes the profile information to company_profile.json\nfunc SaveCompanyProfile(Domain string, profile CompanyProfile) error {\n\tfilename := fmt.Sprintf(PRODUCT_CONFIG_PATH+\"/%s/company_profile.json\", Domain)\n\tdata, err := json.Marshal(profile)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error marshalling company profile: %v\", err)\n\t}\n\terr = os.WriteFile(filename, data, 0644)","sourceCodeStart":430,"sourceCodeEnd":466,"githubUrl":"https://github.com/Billionmail/BillionMail/blob/fc36c76c050c3775c5e899faf7403cf0262d2744/core/internal/service/askai/project.go#L430-L466","documentation":"When company_profile.json exists, ReadCompanyProfile loads it with os.ReadFile. This error wraps a read failure on an existing file — the file passed the FileExists check but could not actually be read, usually due to permissions, the path being a directory, or a TOCTOU deletion between the check and the read.","triggerScenarios":"os.ReadFile(filename) fails though FileExists returned true: permission denied on the file; company_profile.json is a directory; file deleted concurrently between FileExists and ReadFile; I/O error on the underlying storage.","commonSituations":"Profile file created by root, service running as unprivileged user; a directory accidentally named company_profile.json; concurrent initialization racing to create/read the profile; corrupted volume.","solutions":["Read the wrapped %v error for the OS cause (EACCES, EISDIR, ENOENT)","Fix file permissions/ownership so the service user can read company_profile.json","If a directory occupies the name, remove it and let the lazy-create path regenerate the default","Handle the race by attempting ReadFile first and treating os.IsNotExist as 'create default' instead of pre-checking FileExists"],"exampleFix":"// before\nif !public.FileExists(filename) { /* create default */ }\ndata, err := os.ReadFile(filename)\n// after\ndata, err := os.ReadFile(filename)\nif os.IsNotExist(err) { /* create default */ } else if err != nil {\n    return CompanyProfile{}, fmt.Errorf(\"error reading company profile file: %w\", err)\n}","handlingStrategy":"try-catch","validationCode":"p := fmt.Sprintf(PRODUCT_CONFIG_PATH+\"/%s/company_profile.json\", domain)\nif fi, err := os.Stat(p); err == nil {\n    if fi.IsDir() {\n        return fmt.Errorf(\"%s is a directory\", p)\n    }\n    f, err := os.OpenFile(p, os.O_RDONLY, 0)\n    if err != nil {\n        return fmt.Errorf(\"profile unreadable: %w\", err)\n    }\n    f.Close()\n}","typeGuard":null,"tryCatchPattern":"profile, err := ReadCompanyProfile(domain)\nif err != nil && strings.Contains(err.Error(), \"reading company profile file\") {\n    if os.IsPermission(errors.Unwrap(err)) {\n        log.Errorf(\"Permission denied on %s profile\", domain)\n    }\n    // fall back to an empty default profile\n    profile = CompanyProfile{}\n}","preventionTips":["Read-first (treat os.IsNotExist as create-default) instead of FileExists pre-checks","Keep profile files owned/readable by the service user","Never create directories named company_profile.json","Validate file readability in startup health checks"],"tags":["go","filesystem","io","permissions"],"backgroundTag":"file-read-failed","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"}