gofr-dev/gofr · error

%w: %q

Error message

%w: %q

What it means

CopyObject could not find the source object: Retr on the source path returned a not-found-classified error, so the library returns errObjectNotFound wrapping only the source name (no underlying error). The copy was aborted before reading any data.

Solutions

  1. Verify the source exists (StatObject) before copying, or wait/retry until the producer has created it
  2. Check the source name spelling and case
  3. Check the base-path configuration used by buildPath
  4. Handle errors.Is(err, errObjectNotFound) distinctly from transfer failures

Example fix

// before
err := store.CopyObject(ctx, "incoming/a.csv", "done/a.csv")
// after
if _, err := store.StatObject(ctx, "incoming/a.csv"); err != nil {
    return fmt.Errorf("source not ready: %w", err) // retry later
}
err = store.CopyObject(ctx, "incoming/a.csv", "done/a.csv")
Defensive patterns

Strategy: validation

Validate before calling

if _, err := store.StatObject(ctx, source); err != nil {
    return fmt.Errorf("source %q not ready: %w", source, err)
}

Type guard

func isFTPNotFound(err error) bool { return errors.Is(err, errObjectNotFound) }

Try / catch

err := store.CopyObject(ctx, source, dst)
if err != nil && errors.Is(err, errObjectNotFound) {
    // wait for producer or skip; distinguish from transfer errors
}

Prevention

When it happens

Trigger: Calling storageAdapter.CopyObject(ctx, source, dst) where s.conn.Retr(sourcePath) returns an error matched by isFTPNotFoundError.

Common situations: Copy scheduled before the producer created the file, source name typo or case mismatch, wrong base path in buildPath, source removed by a cleanup job concurrently.

Related errors


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

Appendix: source

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

	if source == "" || dest == "" {
		return errEmptySourceOrDest
	}

	if source == dest {
		return errSameSourceAndDest
	}

	if s.conn == nil {
		return errFTPClientNotInitialized
	}

	// Read source file
	sourcePath := s.buildPath(source)

	resp, err := s.conn.Retr(sourcePath)
	if err != nil {
		if isFTPNotFoundError(err) {
			return fmt.Errorf("%w: %q", errObjectNotFound, source)
		}

		return fmt.Errorf("failed to read source object %q: %w", source, err)
	}

	// Read all data from source into memory
	data, err := io.ReadAll(resp)

	closeErr := resp.Close()

	if err != nil {
		return fmt.Errorf("failed to read source object data %q: %w", source, err)
	}

	if closeErr != nil {
		return fmt.Errorf("failed to close source reader for %q: %w", source, closeErr)
	}

View on GitHub (pinned to 187eb24962)