gofr-dev/gofr · error
operation not permitted
Error message
operation not permitted
What it means
ErrOperationNotPermitted is the public sentinel for operations the S3 filesystem cannot perform like a POSIX filesystem. It is returned by Rename when trying to move a file to a different location and by ChDir, since S3 has no working-directory concept. Match with errors.Is(err, s3.ErrOperationNotPermitted).
Source
Thrown at pkg/gofr/datasource/file/s3/fs_dir.go:21
import (
"context"
"errors"
"fmt"
"mime"
"os"
"path"
"path/filepath"
"strings"
"time"
"github.com/aws/aws-sdk-go-v2/aws"
"github.com/aws/aws-sdk-go-v2/service/s3"
"github.com/aws/aws-sdk-go-v2/service/s3/types"
file "gofr.dev/pkg/gofr/datasource/file"
)
var (
ErrOperationNotPermitted = errors.New("operation not permitted")
)
// getBucketName returns the currentS3Bucket.
func getBucketName(filePath string) string {
return strings.Split(filePath, string(filepath.Separator))[0]
}
// getLocation returns the absolute path of the S3 bucket.
func getLocation(bucket string) string {
return path.Join(string(filepath.Separator), bucket)
}
// Mkdir creates a directory and any necessary parent directories in the S3 bucket.
//
// This method creates a pseudo-directory in the S3 bucket by putting objects with the specified path prefixes.
// Since S3 uses a flat storage structure, directories are represented by object keys with trailing slashes.
// The method processes the path segments and ensures that each segment (directory) exists in S3.
func (f *FileSystem) Mkdir(name string, _ os.FileMode) error {View on GitHub (pinned to 187eb24962)
Solutions
- Replace ChDir usage with fully qualified paths (bucket/key) on every call.
- For moves, implement copy+delete (CopyObject then DeleteObject) yourself.
- Abstract behind an interface that offers move/cd only for real filesystem backends, so S3 backends never receive those calls.
Example fix
// before
fs.Chdir("bucket/subdir") // not permitted
// after
f, _ := fs.Open("bucket/subdir/file.txt") // use full path instead Defensive patterns
Strategy: try-catch
Validate before calling
// avoid calling these on S3-backed fs:
var _ = interface{ ChDir() error } // guard with capability check at startup
func supportsChDir(fs any) bool { _, ok := fs.(interface{ ChDir() error }); return ok } Try / catch
err := fsObj.ChDir()
if errors.Is(err, s3datasource.ErrOperationNotPermitted) {
// use fully qualified bucket/key paths instead
} Prevention
- Never call ChDir on S3-backed filesystems; always use full bucket/key paths.
- Replace move operations with explicit CopyObject+DeleteObject.
- Feature-detect capabilities behind an interface so S3 backends never receive unsupported calls.
- Check errors.Is(err, s3.ErrOperationNotPermitted) to branch behavior cleanly.
When it happens
Trigger: 1) Rename(oldname, newname) where the two paths have different parent directories; 2) any call to ChDir on the S3 filesystem.
Common situations: Treating the S3 datasource as a drop-in for os.FileSystem (moving files, changing directories); tools ported from local-disk code paths; attempts to implement directory navigation in a flat key-value store.
Related errors
- %w: renaming as well as moving file to different location is
- 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/9a37a6cad7b38cda.
Report an issue: GitHub.