{"record":{"id":"ff5b87519afc108c","repo":"Billionmail/BillionMail","slug":"error-removing-knowledge-base-file-v","errorCode":null,"errorMessage":"error removing knowledge base file: %v","messagePattern":"error removing knowledge base file: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"core/internal/service/askai/project.go","lineNumber":412,"sourceCode":"\n\tknowledge.UpdateTime = public.GetNowTime()\n\terr = SaveKnowledgeBase(Domain, knowledge)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error saving knowledge base: %v\", err)\n\t}\n\treturn nil\n}\n\n// RemoveKnowledgeBaseFile removes a knowledge base file based on the provided domain and knowledge ID.\n// It constructs the file path, checks if the file exists, and removes it.\nfunc RemoveKnowledgeBaseFile(Domain string, Kid string) error {\n\tfilename := fmt.Sprintf(PRODUCT_CONFIG_PATH+\"/%s/knowledge/%s.json\", Domain, Kid)\n\tif !public.FileExists(filename) {\n\t\treturn fmt.Errorf(\"knowledge base file does not exist: %s\", filename)\n\t}\n\terr := os.Remove(filename)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error removing knowledge base file: %v\", err)\n\t}\n\treturn nil\n}\n\n// ReadCompanyProfile reads the company profile from a JSON file based on the provided domain.\n// It returns a CompanyProfile struct or an error if the file does not exist or cannot be read.\nfunc ReadCompanyProfile(Domain string) (CompanyProfile, error) {\n\tfilename := fmt.Sprintf(PRODUCT_CONFIG_PATH+\"/%s/company_profile.json\", Domain)\n\tif !public.FileExists(filename) {\n\t\tcompanyProfileDefault := CompanyProfile{\n\t\t\tLegalCompanyName: \"\",\n\t\t\tWebSite:          \"\",\n\t\t\tCompanyProfile:   \"\",\n\t\t\tEmail:            \"\",\n\t\t\tPhone:            \"\",\n\t\t\tSupportUrl:       \"\",\n\t\t}\n\t\t// If the company profile file does not exist, return a default profile","sourceCodeStart":394,"sourceCodeEnd":430,"githubUrl":"https://github.com/Billionmail/BillionMail/blob/fc36c76c050c3775c5e899faf7403cf0262d2744/core/internal/service/askai/project.go#L394-L430","documentation":"This error wraps os.Remove failure when deleting the knowledge base JSON file. The FileExists check passed, so the file existed at check time but the removal still failed — typically a permission problem, the path being a directory, or the file being locked/mounted. There is also an inherent TOCTOU race: the file can vanish between FileExists and Remove.","triggerScenarios":"os.Remove(filename) fails despite FileExists returning true: permission denied on the file or its parent directory; <kid>.json is actually a directory; the file was deleted between the check and the remove (race); filesystem is read-only after the check.","commonSituations":"File owned by another user (root-created, service running unprivileged); a directory accidentally created with the .json name; concurrent delete requests racing; immutable files or read-only remounts.","solutions":["Read the wrapped %v error for the OS cause (EACCES, EISDIR, ENOENT)","Fix permissions/ownership on the file or its parent directory","If a directory occupies the name, remove it manually or use os.RemoveAll appropriately","Make removal idempotent: use os.Remove directly and treat ENOENT as success, eliminating the FileExists race"],"exampleFix":"// before\nif !public.FileExists(filename) {\n    return fmt.Errorf(\"knowledge base file does not exist: %s\", filename)\n}\nerr := os.Remove(filename)\n// after\nif err := os.Remove(filename); err != nil && !os.IsNotExist(err) {\n    return fmt.Errorf(\"error removing knowledge base file: %w\", err)\n}","handlingStrategy":"try-catch","validationCode":"p := fmt.Sprintf(PRODUCT_CONFIG_PATH+\"/%s/knowledge/%s.json\", domain, kid)\nif fi, err := os.Stat(p); err == nil && fi.IsDir() {\n    return fmt.Errorf(\"%s is a directory, not a file\", p)\n}\nif err := syscall.Access(filepath.Dir(p), unix.W_OK); err != nil {\n    return fmt.Errorf(\"no write permission on %s\", filepath.Dir(p))\n}","typeGuard":null,"tryCatchPattern":"if err := RemoveKnowledgeBaseFile(domain, kid); err != nil {\n    if strings.Contains(err.Error(), \"removing knowledge base file\") {\n        log.Errorf(\"Delete failed for %s/%s: %v — check perms/locks\", domain, kid, err)\n        // retry with backoff or alert ops\n    }\n}","preventionTips":["Keep the config directory owned by the service user","Guard against creating directories named *.json","Serialize delete operations to avoid concurrent-remove races","Monitor for read-only remounts of the config volume"],"tags":["go","filesystem","permissions","delete"],"backgroundTag":"file-delete-failed","analyzedSha":"fc36c76c050c3775c5e899faf7403cf0262d2744","analyzedAt":"2026-09-05T21:28:54.019Z","contentChangedAt":"2026-09-05T21:28:54.019Z","schemaVersion":2},"datasetVersion":"2026-09-12T22:17:10.623Z"}