Billionmail/BillionMail · error

error reading knowledge base directory: %v

Error message

error reading knowledge base directory: %v

What it means

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.

Source

Thrown at core/internal/service/askai/project.go:340

	if err != nil {
		return fmt.Errorf("error writing knowledge base file: %v", err)
	}
	return nil
}

// GetKnowledgeBaseList retrieves a list of all knowledge bases for a given domain.
// It reads the knowledge base directory, iterates through the files, and returns a slice of KnowledgeInfo structs.
// If the directory does not exist or cannot be read, it returns an error.
func GetKnowledgeBaseList(Domain string) ([]KnowledgeInfo, error) {
	knowledgePath := fmt.Sprintf("%s/%s/knowledge", PRODUCT_CONFIG_PATH, Domain)
	if !public.FileExists(knowledgePath) {
		os.MkdirAll(knowledgePath, os.ModePerm)
		// If the knowledge base directory does not exist, create it
	}

	files, err := os.ReadDir(knowledgePath)
	if err != nil {
		return nil, fmt.Errorf("error reading knowledge base directory: %v", err)
	}

	var knowledgeList []KnowledgeInfo = []KnowledgeInfo{}
	for _, file := range files {
		if !file.IsDir() {
			knowledge, err := ReadKnowledgeBase(Domain, strings.Split(file.Name(), ".")[0])
			if err == nil {
				knowledgeList = append(knowledgeList, knowledge)
			}
		}
	}
	return knowledgeList, nil
}

// GetUUID generates a new UUID using the UUID version 7 and returns it as a string.
// UUID version 7 is a time-based UUID that is suitable for generating unique identifiers.
func GetUUID() string {
	return uuid.Must(uuid.NewV7()).String()

View on GitHub (pinned to fc36c76c05)

Solutions

  1. Inspect the wrapped %v error for the OS cause (ENOENT, ENOTDIR, EACCES)
  2. Verify PRODUCT_CONFIG_PATH/<domain> exists and is writable; fix the ignored MkdirAll error to get a clearer failure
  3. Ensure nothing replaced the knowledge directory with a regular file; recreate the directory
  4. Run the service as a user with write access to PRODUCT_CONFIG_PATH

Example fix

// before
if !public.FileExists(knowledgePath) {
    os.MkdirAll(knowledgePath, os.ModePerm) // error ignored
}
// after
if err := os.MkdirAll(knowledgePath, 0o755); err != nil {
    return nil, fmt.Errorf("error creating knowledge dir: %w", err)
}
Defensive patterns

Strategy: validation

Validate before calling

func ensureKnowledgeDir(domain string) error {
    dir := fmt.Sprintf("%s/%s/knowledge", PRODUCT_CONFIG_PATH, domain)
    fi, err := os.Stat(dir)
    if err == nil && !fi.IsDir() {
        return fmt.Errorf("%s is not a directory", dir)
    }
    return os.MkdirAll(dir, 0o755)
}

Try / catch

list, err := GetKnowledgeBaseList(domain)
if err != nil {
    if strings.Contains(err.Error(), "directory") {
        log.Errorf("Knowledge dir unreadable for %s: %v", domain, err)
        // fall back to empty list or repair the directory
    }
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of Billionmail/BillionMail@fc36c76c05 (2026-09-05). Data as JSON: /api/errors/c2af9d77a40f945c. Report an issue: GitHub.