dutchcoders/transfer.sh · error

Could not delete file.

Error message

Could not delete file.

What it means

deleteHandler calls the storage backend's Delete and, for any error that is not a not-exist error, logs it and returns HTTP 500 'Could not delete file.'. This means the storage backend (local disk, S3, GCS, etc.) failed to delete the object for a reason other than the file being absent.

Source

Thrown at server/handlers.go:962

	vars := mux.Vars(r)

	token := vars["token"]
	filename := vars["filename"]
	deletionToken := vars["deletionToken"]

	if err := s.checkDeletionToken(r.Context(), deletionToken, token, filename); err != nil {
		s.logger.Printf("Error metadata: %s", err.Error())
		http.Error(w, http.StatusText(http.StatusNotFound), http.StatusNotFound)
		return
	}

	err := s.storage.Delete(r.Context(), token, filename)
	if s.storage.IsNotExist(err) {
		http.Error(w, http.StatusText(http.StatusNotFound), http.StatusNotFound)
		return
	} else if err != nil {
		s.logger.Printf("%s", err.Error())
		http.Error(w, "Could not delete file.", http.StatusInternalServerError)
		return
	}
}

func (s *Server) zipHandler(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)

	files := vars["files"]

	zipfilename := fmt.Sprintf("transfersh-%d.zip", uint16(time.Now().UnixNano()))

	w.Header().Set("Content-Type", "application/zip")
	commonHeader(w, zipfilename)

	zw := zip.NewWriter(w)

	for _, key := range strings.Split(files, ",") {
		key = resolveKey(key, s.proxyPath)

View on GitHub (pinned to c37bfd9579)

Solutions

  1. Check server logs — the raw backend error is logged before the 500 is sent; fix the underlying storage error it reports.
  2. Verify the storage directory/bucket permissions allow deletion for the user running the server (writable storage dir, IAM delete permission).
  3. Confirm storage backend configuration (credentials, region, endpoint) is valid and the backend is reachable.
  4. Increase timeouts or check for client-side cancellation; retry the delete.

Example fix

// before
err := s.storage.Delete(r.Context(), token, filename)
// after
ctx, cancel := context.WithTimeout(r.Context(), 30*time.Second)
defer cancel()
if err := s.storage.Delete(ctx, token, filename); err != nil && !s.storage.IsNotExist(err) {
    s.logger.Printf("delete %s/%s: %v", token, filename, err)
}
Defensive patterns

Strategy: try-catch

Validate before calling

// Verify the storage path is writable for deletes before calling the API:
if f, err := os.CreateTemp(storageDir, "probe"); err == nil {
    f.Close(); os.Remove(f.Name())
} else {
    // storage not writable: deletes will 500
}

Try / catch

// client side
switch resp.StatusCode {
case 404: // already gone — treat delete as idempotent success
case 500: // backend failure; check server logs, fix permissions/credentials, then retry
}

Prevention

When it happens

Trigger: s.storage.Delete returns a non-nil, non-IsNotExist error: permission denied on the storage dir/bucket, storage backend unreachable, request context canceled or timed out mid-delete, or a cloud API error other than NoSuchKey.

Common situations: Read-only mount or wrong permissions on the storage directory after a redeploy; expired/misconfigured cloud credentials lacking delete permission; network partition or throttling from the object store; client disconnecting and canceling the request context.

Related errors


AI-assisted analysis of dutchcoders/transfer.sh@c37bfd9579 (2026-09-05). Data as JSON: /api/errors/ca5c3cd216453bb8. Report an issue: GitHub.