Tencent/WeKnora · error
failed to delete file: %w
Error message
failed to delete file: %w
What it means
DeleteFile wraps the error from os.Remove(resolved) after path validation succeeded, meaning the file is inside baseDir but could not be removed. The wrapped OS error distinguishes a missing file (ENOENT), a permission problem (EACCES/EPERM), or a directory-not-empty case. Nothing is deleted when this fires.
Source
Thrown at internal/application/service/file/local.go:150
}
// DeleteFile removes a file from the local file system
// Returns an error if deletion fails
// 路径必须在 baseDir 下,防止路径遍历(如 ../../)
func (s *localFileService) DeleteFile(ctx context.Context, filePath string) error {
logger.Infof(ctx, "Deleting file: %s", filePath)
candidate := s.normalizePathForBase(filePath)
resolved, err := secutils.SafePathUnderBase(s.baseDir, candidate)
if err != nil {
logger.Errorf(ctx, "Path traversal denied for DeleteFile: %v", err)
return fmt.Errorf("invalid file path: %w", err)
}
err = os.Remove(resolved)
if err != nil {
logger.Errorf(ctx, "Failed to delete file: %v", err)
return fmt.Errorf("failed to delete file: %w", err)
}
logger.Info(ctx, "File deleted successfully")
return nil
}
// CopyFile copies an existing local object to a new knowledge-owned object.
// The destination uses the same layout as SaveFile (baseDir/{tenantID}/{knowledgeID}/{unique}{ext}),
// and the copy is a real byte-for-byte copy (no hardlink) so deleting the source
// never affects it. Returns ErrCrossBackendCopy when srcPath is not a local path.
func (s *localFileService) CopyFile(ctx context.Context,
srcPath string, tenantID uint64, knowledgeID string,
) (string, error) {
// Only local paths are accepted. A provider scheme other than local://
// (e.g. s3://, minio://) means a cross-backend copy, which this service
// does not support. Legacy bare/absolute paths have no scheme and pass.
if i := strings.Index(srcPath, "://"); i >= 0 && srcPath[:i+3] != localScheme {
return "", fmt.Errorf("local file service cannot copy %q: %w", srcPath, ErrCrossBackendCopy)View on GitHub (pinned to 988cbb0330)
Solutions
- Treat os.ErrNotExist as success/idempotent delete in the caller (errors.Is(err, fs.ErrNotExist))
- Check directory write permission on the file's parent (rm requires write on the dir) and fix ownership
- Verify the storage volume is mounted read-write
- Skip deleting if a concurrent cleanup job may have already removed the file
Example fix
// before: double-delete surfaces a confusing error
if err := svc.DeleteFile(ctx, path); err != nil {
return err
}
// after: make delete idempotent
if err := svc.DeleteFile(ctx, path); err != nil && !errors.Is(err, os.ErrNotExist) {
return err
} Defensive patterns
Strategy: try-catch
Try / catch
err := svc.DeleteFile(ctx, path)
if err != nil {
if errors.Is(err, os.ErrNotExist) {
return nil // idempotent delete
}
return fmt.Errorf("failed to delete file: %w", err)
} Prevention
- Make deletes idempotent by treating ErrNotExist as success
- Ensure the service user can write to the file's parent directory
- Mount the storage volume read-write and verify after deploys
- Avoid concurrent delete + cleanup jobs on the same files
When it happens
Trigger: os.Remove fails because the file does not exist (already deleted or never saved), the service user lacks write permission on the containing directory, the path resolves to a non-empty directory, or the volume is read-only.
Common situations: Double-delete from a retry or concurrent requests; storage volume mounted read-only; ownership drift after container restart; cleanup job racing with an explicit delete.
Related errors
- failed to open file: %w
- failed to create file: %w
- failed to load script: %w
- storage directory not accessible: %w
- storage path is not a directory: %s
AI-assisted analysis of Tencent/WeKnora@988cbb0330 (2026-09-02).
Data as JSON: /api/errors/c11b2bac2ed7254f.
Report an issue: GitHub.