{"record":{"id":"c2af9d77a40f945c","repo":"Billionmail/BillionMail","slug":"error-reading-knowledge-base-directory-v","errorCode":null,"errorMessage":"error reading knowledge base directory: %v","messagePattern":"error reading knowledge base directory: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"core/internal/service/askai/project.go","lineNumber":340,"sourceCode":"\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}\n\n\tvar knowledgeList []KnowledgeInfo = []KnowledgeInfo{}\n\tfor _, file := range files {\n\t\tif !file.IsDir() {\n\t\t\tknowledge, err := ReadKnowledgeBase(Domain, strings.Split(file.Name(), \".\")[0])\n\t\t\tif err == nil {\n\t\t\t\tknowledgeList = append(knowledgeList, knowledge)\n\t\t\t}\n\t\t}\n\t}\n\treturn knowledgeList, nil\n}\n\n// GetUUID generates a new UUID using the UUID version 7 and returns it as a string.\n// UUID version 7 is a time-based UUID that is suitable for generating unique identifiers.\nfunc GetUUID() string {\n\treturn uuid.Must(uuid.NewV7()).String()","sourceCodeStart":322,"sourceCodeEnd":358,"githubUrl":"https://github.com/Billionmail/BillionMail/blob/fc36c76c050c3775c5e899faf7403cf0262d2744/core/internal/service/askai/project.go#L322-L358","documentation":"GetKnowledgeBaseList reads the per-domain knowledge directory via os.ReadDir to enumerate knowledge base JSON files. This error wraps any ReadDir failure. Although the function attempts to create the directory with MkdirAll beforehand, that error is ignored, so a failed creation (permission, read-only FS) surfaces as this ReadDir error.","triggerScenarios":"os.ReadDir(knowledgePath) fails: the directory does not exist because the preceding MkdirAll failed silently (ignored error); the path exists but is a file, not a directory; permission denied; PRODUCT_CONFIG_PATH is misconfigured.","commonSituations":"PRODUCT_CONFIG_PATH pointing to an unwritable or read-only location so directory auto-creation fails; a regular file named 'knowledge' shadowing the directory; running with a different user than the one who created config dirs; corrupted volume mount.","solutions":["Inspect the wrapped %v error for the OS cause (ENOENT, ENOTDIR, EACCES)","Verify PRODUCT_CONFIG_PATH/<domain> exists and is writable; fix the ignored MkdirAll error to get a clearer failure","Ensure nothing replaced the knowledge directory with a regular file; recreate the directory","Run the service as a user with write access to PRODUCT_CONFIG_PATH"],"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 nil, fmt.Errorf(\"error creating knowledge dir: %w\", err)\n}","handlingStrategy":"validation","validationCode":"func ensureKnowledgeDir(domain string) error {\n    dir := fmt.Sprintf(\"%s/%s/knowledge\", PRODUCT_CONFIG_PATH, domain)\n    fi, err := os.Stat(dir)\n    if err == nil && !fi.IsDir() {\n        return fmt.Errorf(\"%s is not a directory\", dir)\n    }\n    return os.MkdirAll(dir, 0o755)\n}","typeGuard":null,"tryCatchPattern":"list, err := GetKnowledgeBaseList(domain)\nif err != nil {\n    if strings.Contains(err.Error(), \"directory\") {\n        log.Errorf(\"Knowledge dir unreadable for %s: %v\", domain, err)\n        // fall back to empty list or repair the directory\n    }\n}","preventionTips":["Check MkdirAll errors instead of ignoring them","Ensure nothing creates a file named 'knowledge' in the domain config dir","Confirm PRODUCT_CONFIG_PATH matches across all services","Boot-time check that the config root is readable/writable"],"tags":["go","filesystem","io","directory"],"backgroundTag":"directory-read-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"}