Tencent/WeKnora · error

failed to create directory: %w

Error message

failed to create directory: %w

What it means

localFileService.SaveFile wraps os.MkdirAll errors with "failed to create directory: %w". The directory path passed traversal validation but the OS refused to create baseDir/tenantID/knowledgeID — typically permission denied, a file occupying the path, read-only filesystem, or disk/exhausted-inode conditions.

Source

Thrown at internal/application/service/file/local.go:67

// The file is stored in a directory structure: baseDir/tenantID/knowledgeID/filename
// Returns the full file path or an error if saving fails
func (s *localFileService) SaveFile(ctx context.Context,
	file *multipart.FileHeader, tenantID uint64, knowledgeID string,
) (string, error) {
	logger.Info(ctx, "Starting to save file locally")
	logger.Infof(ctx, "File information: name=%s, size=%d, tenant ID=%d, knowledge ID=%s",
		file.Filename, file.Size, tenantID, knowledgeID)

	// Create storage directory with tenant and knowledge ID
	dir := filepath.Join(s.baseDir, fmt.Sprintf("%d", tenantID), knowledgeID)
	if _, err := secutils.SafePathUnderBase(s.baseDir, dir); err != nil {
		logger.Errorf(ctx, "Path traversal denied for SaveFile dir: %v", err)
		return "", fmt.Errorf("invalid path: %w", err)
	}
	logger.Infof(ctx, "Creating directory: %s", dir)
	if err := os.MkdirAll(dir, 0o755); err != nil {
		logger.Errorf(ctx, "Failed to create directory: %v", err)
		return "", fmt.Errorf("failed to create directory: %w", err)
	}

	// Generate unique filename using timestamp
	ext := filepath.Ext(file.Filename)
	filename := fmt.Sprintf("%d%s", time.Now().UnixNano(), ext)
	filePath := filepath.Join(dir, filename)
	logger.Infof(ctx, "Generated file path: %s", filePath)

	// Open source file for reading
	logger.Info(ctx, "Opening source file")
	src, err := file.Open()
	if err != nil {
		logger.Errorf(ctx, "Failed to open source file: %v", err)
		return "", fmt.Errorf("failed to open file: %w", err)
	}
	defer src.Close()

	// Create destination file for writing

View on GitHub (pinned to 988cbb0330)

Solutions

  1. Check the wrapped errno: EACCES → chown/chmod baseDir so the service user has write access (chown -R appuser baseDir; chmod u+w).
  2. ENOTDIR → remove or rename the file that occupies the tenant/knowledge path component.
  3. EROFS → remount the volume read-write or point baseDir at a writable volume.
  4. ENOSPC → free disk space or expand the volume; monitor disk usage for the storage mount.
  5. Verify the path passes validation but is sane on disk: ls -la baseDir/tenantID to spot conflicting entries.

Example fix

// before
// container user uid=1000, baseDir owned by root:root 755 → MkdirAll EACCES
// after
// deploy.yaml
securityContext: { runAsUser: 1000 }
// plus initContainer: chown -R 1000:1000 /data/weknora/files
Defensive patterns

Strategy: try-catch

Validate before calling

// pre-flight writability check
test := filepath.Join(baseDir, ".write-test")
if err := os.WriteFile(test, nil, 0o644); err != nil { /* storage not writable */ }
os.Remove(test)

Try / catch

if _, err := svc.SaveFile(ctx, fh, tenantID, knowledgeID); err != nil {
	if strings.Contains(err.Error(), "failed to create directory") {
		// check errno: EACCES→permissions, EROFS→mount, ENOSPC→disk
		return StorageUnavailable
	}
	return err
}

Prevention

When it happens

Trigger: os.MkdirAll fails with EACCES (service user can't write under baseDir), ENOTDIR (a component like baseDir/tenantID exists as a file), EROFS (read-only mount), or ENOSPC.

Common situations: Container runs as non-root while baseDir is root-owned; PVC mounted read-only; a file named like a tenant ID exists (e.g. created by touch or collision); disk full after large uploads; SELinux/AppArmor blocking writes.

Understand the failure class

Background: mkdir permission denied (EACCES): failed to create directory errors explained — this error's family across 32 libraries.

Related errors


AI-assisted analysis of Tencent/WeKnora@988cbb0330 (2026-09-02). Data as JSON: /api/errors/1e817b292ef7e757. Report an issue: GitHub.