gofr-dev/gofr · error
%w: renaming as well as moving file to different location is
Error message
%w: renaming as well as moving file to different location is not allowed
What it means
Rename in the S3 filesystem only supports renaming in place: S3 objects cannot be atomically moved between prefixes, so when oldname and newname have different directory components the call is refused with this wrap of the public sentinel ErrOperationNotPermitted. errors.Is(err, s3.ErrOperationNotPermitted) matches.
Source
Thrown at pkg/gofr/datasource/file/s3/fs.go:347
st := statusErr
defer f.sendOperationStats(&FileLog{
Operation: "RENAME",
Location: getLocation(f.config.BucketName),
Status: &st,
Message: &msg,
}, time.Now())
// check if they have the same name or not
if oldname == newname {
f.logger.Logf("%q & %q are same", oldname, newname)
return nil
}
// check if both exist at same location or not
if path.Dir(oldname) != path.Dir(newname) {
f.logger.Errorf("%q & %q are not in same location", oldname, newname)
return fmt.Errorf("%w: renaming as well as moving file to different location is not allowed", ErrOperationNotPermitted)
}
// check if it is a directory
if path.Ext(oldname) == "" {
return f.renameDirectory(&st, &msg, oldname, newname)
}
// check if they are of the same type or not
if path.Ext(oldname) != path.Ext(newname) {
f.logger.Errorf("new file must be same as the old file type")
return fmt.Errorf("%w: new filename must match the old file's type", errIncorrectFileType)
}
_, err := f.conn.CopyObject(context.TODO(), &s3.CopyObjectInput{
Bucket: aws.String(f.config.BucketName),
// The source object can be up to 5 GB.
// If the source object is an object that was uploaded by using a multipart upload, the object copy
// will be a single part object after the source object is copied to the destination bucket.View on GitHub (pinned to 187eb24962)
Solutions
- Rename only within the same directory/prefix: same path.Dir for both names.
- Implement a move manually: CopyObject to the new key followed by DeleteObject on the old key.
- If using the gofr fs API, first change directory/bucket context appropriately, or restructure code to upload directly to the target prefix.
Example fix
// before
fs.Rename("bucket/logs/old.txt", "bucket/archive/old.txt") // not permitted
// after
// copy then delete
fs.Copy? -> use conn.CopyObject(newKey) + DeleteObject(oldKey), or rename in place:
fs.Rename("bucket/logs/old.txt", "bucket/logs/renamed.txt") Defensive patterns
Strategy: validation
Validate before calling
func sameDir(old, new string) bool { return path.Dir(old) == path.Dir(new) }
// guard before calling:
if !sameDir(oldName, newName) { /* do copy+delete instead of Rename */ } Try / catch
if err := fs.Rename(old, new); err != nil {
if errors.Is(err, s3datasource.ErrOperationNotPermitted) {
// fallback: CopyObject(new) + DeleteObject(old)
}
return err
} Prevention
- Only rename within the same prefix/directory.
- Implement an explicit Move(ctx, src, dst) helper using CopyObject+DeleteObject.
- Don't port os.Rename move semantics blindly to S3 backends.
- Keep bucket/prefix layout stable to avoid accidental cross-prefix renames.
When it happens
Trigger: Calling Rename(oldname, newname) where path.Dir(oldname) != path.Dir(newname), e.g. Rename("bucket/dir1/a.txt", "bucket/dir2/a.txt") — effectively a move across locations.
Common situations: Porting POSIX os.Rename-based code to the S3 filesystem expecting move semantics; reorganizing objects into different prefixes; generic file-moving utilities wired to the S3 backend.
Related errors
- operation not permitted
- incorrect file type
- %w: new filename must match the old file's type
- response retrieved is nil
- s3 backend did not honor the requested byte range
AI-assisted analysis of gofr-dev/gofr@187eb24962 (2026-09-01).
Data as JSON: /api/errors/dd74df487bc4f047.
Report an issue: GitHub.