Tencent/WeKnora · error
storage path is not a directory: %s
Error message
storage path is not a directory: %s
What it means
localFileService.CheckConnectivity returns "storage path is not a directory: %s" when os.Stat succeeds but the target is a regular file, symlink to a file, or other non-directory. The configured baseDir exists but can't serve as a storage root.
Source
Thrown at internal/application/service/file/local.go:33
secutils "github.com/Tencent/WeKnora/internal/utils"
)
// localFileService implements the FileService interface for local file system storage
type localFileService struct {
baseDir string // Base directory for file storage
externalURL string // External URL base for presigned URL generation (empty = return local:// paths)
}
const localScheme = "local://"
// CheckConnectivity verifies the local storage directory exists and is accessible.
func (s *localFileService) CheckConnectivity(ctx context.Context) error {
info, err := os.Stat(s.baseDir)
if err != nil {
return fmt.Errorf("storage directory not accessible: %w", err)
}
if !info.IsDir() {
return fmt.Errorf("storage path is not a directory: %s", s.baseDir)
}
return nil
}
// NewLocalFileService creates a new local file service instance.
// externalURL is the externally-reachable base URL (e.g. "https://weknora.example.com");
// when set, GetFileURL returns presigned HTTP URLs instead of local:// paths.
func NewLocalFileService(baseDir, externalURL string) interfaces.FileService {
return &localFileService{
baseDir: baseDir,
externalURL: strings.TrimRight(externalURL, "/"),
}
}
// SaveFile stores an uploaded file to the local file system
// 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,View on GitHub (pinned to 988cbb0330)
Solutions
- Remove the file at that path and create a directory: rm <path> && mkdir -p <path> (after confirming the file isn't needed).
- Fix the storage base-dir config/env to the actual intended directory path.
- In Docker/K8s, correct the volume spec so a directory (or emptyDir/PVC) is mounted at the storage path, not a single file.
- Fix provisioning/entrypoint scripts to use mkdir -p rather than touch for the storage path.
Example fix
// before # provisioning.sh touch /data/weknora/files // after # provisioning.sh mkdir -p /data/weknora/files
Defensive patterns
Strategy: validation
Validate before calling
info, err := os.Stat(baseDir)
if err == nil && !info.IsDir() {
return fmt.Errorf("%q exists but is not a directory", baseDir)
} Try / catch
if err := svc.CheckConnectivity(ctx); err != nil {
if strings.Contains(err.Error(), "not a directory") {
// operator action required: fix path or replace file with dir
}
} Prevention
- Use mkdir -p, never touch, when provisioning the storage path
- Mount directories (PVC/emptyDir), not single files, at the storage path in containers
- Keep the storage base dir separate from config/socket paths
When it happens
Trigger: baseDir points at an existing regular file — e.g. someone created the path with touch, a config value collides with a file, a bind-mount mounted a file where a directory was expected, or an old symlink now resolves to a file.
Common situations: Docker bind-mounting a single file onto the storage path; config pointing at a config file or socket path by mistake; provisioning script using touch instead of mkdir; leftover file from a failed migration.
Related errors
- storage directory not accessible: %w
- failed to create directory: %w
- custom agent configuration is required for agent QA
- summary model (model_id) is not configured in custom agent s
- rerank model is not configured: please set rerank_model_id o
AI-assisted analysis of Tencent/WeKnora@988cbb0330 (2026-09-02).
Data as JSON: /api/errors/c82ee57eef6549c8.
Report an issue: GitHub.