gofr-dev/gofr · error

source and destination are the same

Error message

source and destination are the same

What it means

errSameSourceAndDest is returned by CopyObject when the source and destination names are identical. Copying an object onto itself is a no-op at best and data loss at worst, so the adapter rejects it up front.

Source

Thrown at pkg/gofr/datasource/file/ftp/storage_adapter.go:24

	"errors"
	"fmt"
	"io"
	"path"
	"strings"
	"time"

	"github.com/jlaffaye/ftp"
	"gofr.dev/pkg/gofr/datasource/file"
)

var (
	// Storage adapter errors.
	errFTPConfigNil            = errors.New("FTP config is nil")
	errFTPClientNotInitialized = errors.New("FTP client is not initialized")
	errEmptyObjectName         = errors.New("object name is empty")
	errInvalidOffset           = errors.New("invalid offset: must be >= 0")
	errEmptySourceOrDest       = errors.New("source and destination names cannot be empty")
	errSameSourceAndDest       = errors.New("source and destination are the same")
	errFailedToCreateReader    = errors.New("failed to create reader")
	errFailedToCreateWriter    = errors.New("failed to create writer")
	errObjectNotFound          = errors.New("object not found")
	errFailedToGetObjectAttrs  = errors.New("failed to get object attrs")
	errFailedToDeleteObject    = errors.New("failed to delete object")
	errFailedToListObjects     = errors.New("failed to list objects")
	errFailedToListDirectory   = errors.New("failed to list directory")
	errWriterAlreadyClosed     = errors.New("writer already closed")
	errFTPConfigInvalid        = errors.New("invalid FTP configuration: host and port are required")
)

// Config represents the FTP configuration.
type Config struct {
	Host        string        // FTP server hostname
	User        string        // FTP username
	Password    string        // FTP password
	Port        int           // FTP port
	RemoteDir   string        // Remote directory path. Base Path for all FTP Operations.

View on GitHub (pinned to 187eb24962)

Solutions

  1. Compare src and dst before copying and skip the call (or return a friendly no-op) when they match.
  2. Ensure rename flows generate a genuinely different destination name.
  3. Normalize names (path cleaning, case) so identical logical paths compare equal before deciding to copy.

Example fix

// before
err := adapter.CopyObject(ctx, oldName, newName) // newName == oldName
// after
if oldName == newName {
    return nil // nothing to do
}
err := adapter.CopyObject(ctx, oldName, newName)
Defensive patterns

Strategy: validation

Validate before calling

if src == dst {
    return nil // self-copy is a no-op; skip the network call
}

Type guard

func isSelfCopy(src, dst string) bool { return src == dst }

Try / catch

if isSelfCopy(src, dst) { return nil }
if err := adapter.CopyObject(ctx, src, dst); errors.Is(err, errSameSourceAndDest) {
    return nil // treat as no-op
}

Prevention

When it happens

Trigger: Calling CopyObject(ctx, name, name) — commonly from a rename implementation that forgot to change the destination, or user input where new name equals old name.

Common situations: Rename UIs accepting unchanged names; logic defaulting dst to src when a new name was not provided.

Related errors


AI-assisted analysis of gofr-dev/gofr@187eb24962 (2026-09-01). Data as JSON: /api/errors/d92b4454ec7a89ef. Report an issue: GitHub.