Billionmail/BillionMail · error
error removing knowledge base file: %v
Error message
error removing knowledge base file: %v
What it means
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.
Source
Thrown at core/internal/service/askai/project.go:412
knowledge.UpdateTime = public.GetNowTime()
err = SaveKnowledgeBase(Domain, knowledge)
if err != nil {
return fmt.Errorf("error saving knowledge base: %v", err)
}
return nil
}
// RemoveKnowledgeBaseFile removes a knowledge base file based on the provided domain and knowledge ID.
// It constructs the file path, checks if the file exists, and removes it.
func RemoveKnowledgeBaseFile(Domain string, Kid string) error {
filename := fmt.Sprintf(PRODUCT_CONFIG_PATH+"/%s/knowledge/%s.json", Domain, Kid)
if !public.FileExists(filename) {
return fmt.Errorf("knowledge base file does not exist: %s", filename)
}
err := os.Remove(filename)
if err != nil {
return fmt.Errorf("error removing knowledge base file: %v", err)
}
return nil
}
// ReadCompanyProfile reads the company profile from a JSON file based on the provided domain.
// It returns a CompanyProfile struct or an error if the file does not exist or cannot be read.
func ReadCompanyProfile(Domain string) (CompanyProfile, error) {
filename := fmt.Sprintf(PRODUCT_CONFIG_PATH+"/%s/company_profile.json", Domain)
if !public.FileExists(filename) {
companyProfileDefault := CompanyProfile{
LegalCompanyName: "",
WebSite: "",
CompanyProfile: "",
Email: "",
Phone: "",
SupportUrl: "",
}
// If the company profile file does not exist, return a default profileView on GitHub (pinned to fc36c76c05)
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
Example fix
// before
if !public.FileExists(filename) {
return fmt.Errorf("knowledge base file does not exist: %s", filename)
}
err := os.Remove(filename)
// after
if err := os.Remove(filename); err != nil && !os.IsNotExist(err) {
return fmt.Errorf("error removing knowledge base file: %w", err)
} Defensive patterns
Strategy: try-catch
Validate before calling
p := fmt.Sprintf(PRODUCT_CONFIG_PATH+"/%s/knowledge/%s.json", domain, kid)
if fi, err := os.Stat(p); err == nil && fi.IsDir() {
return fmt.Errorf("%s is a directory, not a file", p)
}
if err := syscall.Access(filepath.Dir(p), unix.W_OK); err != nil {
return fmt.Errorf("no write permission on %s", filepath.Dir(p))
} Try / catch
if err := RemoveKnowledgeBaseFile(domain, kid); err != nil {
if strings.Contains(err.Error(), "removing knowledge base file") {
log.Errorf("Delete failed for %s/%s: %v — check perms/locks", domain, kid, err)
// retry with backoff or alert ops
}
} Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- error reading project configuration file: %v
- error writing project configuration file: %v
- error writing knowledge base file: %v
- error creating company profile file: %v
- error reading company profile file: %v
AI-assisted analysis of Billionmail/BillionMail@fc36c76c05 (2026-09-05).
Data as JSON: /api/errors/ff5b87519afc108c.
Report an issue: GitHub.