{"record":{"id":"c990e5e4a8eab9f8","repo":"Billionmail/BillionMail","slug":"error-saving-knowledge-base-v","errorCode":null,"errorMessage":"error saving knowledge base: %v","messagePattern":"error saving knowledge base: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"core/internal/service/askai/project.go","lineNumber":398,"sourceCode":"// If the knowledge base does not exist or cannot be read, it returns an error.\nfunc ModifyKnowledgeBaseFile(Domain string, Kid string, Title string, Content string) error {\n\tknowledge, err := ReadKnowledgeBase(Domain, Kid)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error reading knowledge base: %v\", err)\n\t}\n\n\t// Update the knowledge base information\n\tif Title != \"\" {\n\t\tknowledge.Title = Title\n\t}\n\tif Content != \"\" {\n\t\tknowledge.Content = Content\n\t}\n\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","sourceCodeStart":380,"sourceCodeEnd":416,"githubUrl":"https://github.com/Billionmail/BillionMail/blob/fc36c76c050c3775c5e899faf7403cf0262d2744/core/internal/service/askai/project.go#L380-L416","documentation":"After reading and mutating the KnowledgeInfo (title/content/update time), ModifyKnowledgeBaseFile persists it via SaveKnowledgeBase. This error wraps any SaveKnowledgeBase failure — marshalling or, far more commonly, writing the JSON file. The read succeeded but the save failed, so the update was not persisted.","triggerScenarios":"SaveKnowledgeBase fails while writing <kid>.json: parent directory missing/unwritable (MkdirAll error ignored), permission denied on the file, disk full, or Kid path characters creating an invalid path.","commonSituations":"Read-only volume or full disk at write time; ownership mismatch (file created by root, service now running as another user); PRODUCT_CONFIG_PATH config drift between processes; Kid containing path separators.","solutions":["Read the wrapped inner error ('error writing knowledge base file' vs 'error marshalling knowledge base') to isolate the cause","Check write permissions and disk space for PRODUCT_CONFIG_PATH/<domain>/knowledge","Ensure the service user can overwrite the existing <kid>.json file (chown/chmod)","Verify Domain/Kid contain no invalid path characters"],"exampleFix":"// before\nerr = os.WriteFile(filename, configStr, os.ModePerm)\n// after\nif err := os.WriteFile(filename, configStr, 0o644); err != nil {\n    return fmt.Errorf(\"error writing knowledge base file %s: %w\", filename, err)\n}","handlingStrategy":"try-catch","validationCode":"if err := canWriteKnowledgeDir(domain); err != nil {\n    return fmt.Errorf(\"cannot persist knowledge base: %w\", err)\n}\nif !knowledgeBaseExists(domain, kid) {\n    return fmt.Errorf(\"knowledge base %s not found\", kid)\n}","typeGuard":null,"tryCatchPattern":"if err := ModifyKnowledgeBaseFile(domain, kid, title, content); err != nil {\n    if strings.Contains(err.Error(), \"saving knowledge base\") {\n        log.Errorf(\"Update not persisted for %s/%s: %v\", domain, kid, err)\n        // retry or surface write-failure to the API caller\n    }\n}","preventionTips":["Ensure disk has free space and the config dir is writable before updates","Keep the service user as owner of knowledge files it created","Monitor the wrapped SaveKnowledgeBase error to distinguish read vs save failures","Implement a retry with backoff for transient I/O errors"],"tags":["go","filesystem","io","persistence"],"backgroundTag":"file-write-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"}