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

  1. Treat os.ErrNotExist as success/idempotent delete in the caller (errors.Is(err, fs.ErrNotExist))
  2. Check directory write permission on the file's parent (rm requires write on the dir) and fix ownership
  3. Verify the storage volume is mounted read-write
  4. 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

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


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