{"record":{"id":"dab497508d763d45","repo":"Billionmail/BillionMail","slug":"error-writing-knowledge-base-file-v","errorCode":null,"errorMessage":"error writing knowledge base file: %v","messagePattern":"error writing knowledge base file: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"core/internal/service/askai/project.go","lineNumber":323,"sourceCode":"}\n\n// SaveKnowledgeBase saves the provided KnowledgeInfo to a JSON file based on the domain and knowledge ID.\n// It creates the directory if it does not exist and writes the knowledge information to a JSON file\nfunc SaveKnowledgeBase(Domain string, knowledge KnowledgeInfo) error {\n\tknowledgePath := fmt.Sprintf(\"%s/%s/knowledge\", PRODUCT_CONFIG_PATH, Domain)\n\tif !public.FileExists(knowledgePath) {\n\t\tos.MkdirAll(knowledgePath, os.ModePerm)\n\t}\n\tfilename := fmt.Sprintf(\"%s/%s.json\", knowledgePath, knowledge.Kid)\n\n\tconfigStr, err := json.MarshalIndent(knowledge, \"\", \"  \")\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error marshalling knowledge base: %v\", err)\n\t}\n\n\terr = os.WriteFile(filename, configStr, os.ModePerm)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error writing knowledge base file: %v\", err)\n\t}\n\treturn nil\n}\n\n// GetKnowledgeBaseList retrieves a list of all knowledge bases for a given domain.\n// It reads the knowledge base directory, iterates through the files, and returns a slice of KnowledgeInfo structs.\n// If the directory does not exist or cannot be read, it returns an error.\nfunc GetKnowledgeBaseList(Domain string) ([]KnowledgeInfo, error) {\n\tknowledgePath := fmt.Sprintf(\"%s/%s/knowledge\", PRODUCT_CONFIG_PATH, Domain)\n\tif !public.FileExists(knowledgePath) {\n\t\tos.MkdirAll(knowledgePath, os.ModePerm)\n\t\t// If the knowledge base directory does not exist, create it\n\t}\n\n\tfiles, err := os.ReadDir(knowledgePath)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"error reading knowledge base directory: %v\", err)\n\t}","sourceCodeStart":305,"sourceCodeEnd":341,"githubUrl":"https://github.com/Billionmail/BillionMail/blob/fc36c76c050c3775c5e899faf7403cf0262d2744/core/internal/service/askai/project.go#L305-L341","documentation":"After successfully marshalling the KnowledgeInfo struct, SaveKnowledgeBase writes the JSON bytes to <configPath>/<domain>/knowledge/<kid>.json with os.WriteFile. This error wraps any failure of that write: missing parent directory, permission denied, disk full, or the target path being a directory. The directory creation via os.MkdirAll on line 312 ignores its own error, so a failed mkdir surfaces here instead.","triggerScenarios":"os.WriteFile fails because: the knowledge directory does not exist and MkdirAll silently failed (ignored error on line 312); the process lacks write permission on PRODUCT_CONFIG_PATH; the disk is full; <kid>.json exists as a directory; the path contains invalid characters from Domain/Kid.","commonSituations":"Read-only container volume or read-only filesystem mount; PRODUCT_CONFIG_PATH misconfigured to a non-writable location; running the service as a non-root user after files were created by root; domain or Kid containing path separators/invalid chars creating a broken path; disk quota exhausted.","solutions":["Read the wrapped %v error to identify the OS-level cause (ENOENT, EACCES, ENOSPC, EISDIR)","Verify the parent directory exists and is writable: check PRODUCT_CONFIG_PATH/<domain>/knowledge permissions; fix MkdirAll to check its error instead of ignoring it","Ensure the process user owns/has write access to PRODUCT_CONFIG_PATH (chown/chmod or fix the volume mount)","Verify Kid and Domain contain no path separators or invalid filesystem characters","Check disk space/quotas with df"],"exampleFix":"// before\nif !public.FileExists(knowledgePath) {\n    os.MkdirAll(knowledgePath, os.ModePerm) // error ignored\n}\n// after\nif err := os.MkdirAll(knowledgePath, 0o755); err != nil {\n    return fmt.Errorf(\"error creating knowledge dir: %w\", err)\n}","handlingStrategy":"validation","validationCode":"func canWriteKnowledgeDir(domain string) error {\n    dir := fmt.Sprintf(\"%s/%s/knowledge\", PRODUCT_CONFIG_PATH, domain)\n    if err := os.MkdirAll(dir, 0o755); err != nil {\n        return err\n    }\n    f, err := os.CreateTemp(dir, \".wtest*\")\n    if err != nil {\n        return err\n    }\n    f.Close()\n    return os.Remove(f.Name())\n}","typeGuard":null,"tryCatchPattern":"if err := SaveKnowledgeBase(domain, kb); err != nil {\n    var pe *fs.PathError\n    if errors.As(err, &pe) || strings.Contains(err.Error(), \"writing\") {\n        log.Errorf(\"KB write failed for %s: %v — check permissions/disk\", kb.Kid, err)\n    }\n}","preventionTips":["Verify PRODUCT_CONFIG_PATH is on a writable volume at startup","Run a write-probe health check on boot","Run the service under a user that owns the config directory","Monitor disk space; alert before ENOSPC","Validate Domain/Kid contain no path separators"],"tags":["go","filesystem","io","permissions"],"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"}