juicedata/juicefs · warning

skip special file %s for jfs: %w

Error message

skip special file %s for jfs: %w

What it means

The JuiceFS object-storage adapter (jfs backend for gateway/sync) refuses Put operations whose key resolves to a JuiceFS internal special file (vfs.IsSpecialName), returning the error wrapped with utils.ErrSkipped so sync/gateway can skip it. JuiceFS reserves names like .accesslog, .stats, .config etc. for its control files, so external writes to them must be rejected.

Source

Thrown at cmd/object.go:128

		_, _ = f.Seek(ctx, off, io.SeekStart)
	}
	if limit <= 0 {
		limit = 1 << 62
	}
	return &jFile{f, limit}, nil
}

var bufPool = sync.Pool{
	New: func() interface{} {
		buf := make([]byte, 128<<10)
		return &buf
	},
}

func (j *juiceFS) Put(rCtx context.Context, key string, in io.Reader, getters ...object.AttrGetter) (err error) {
	ctx := meta.WrapWithoutCancel(rCtx, pid, uid, []uint32{gid})
	if vfs.IsSpecialName(key) {
		return fmt.Errorf("skip special file %s for jfs: %w", key, utils.ErrSkipped)
	}
	p := j.path(key)
	if strings.HasSuffix(p, "/") {
		eno := j.jfs.MkdirAll(ctx, p, 0777, j.umask)
		return toError(eno)
	}
	var tmp string
	if object.PutInplace {
		tmp = p
	} else {
		name := path.Base(p)
		if len(name) > 200 {
			name = name[:200]
		}
		tmp = object.TmpFilePath(p, name)
		defer func() {
			if err != nil {
				if e := j.jfs.Delete(ctx, tmp); e != 0 && !errors.Is(e, syscall.ENOENT) {

View on GitHub (pinned to c9a67b23e8)

Solutions

  1. Rename or exclude the reserved-name file from the source of the sync/put (use sync --exclude patterns).
  2. If produced by the gateway, have the client use a different object key.
  3. Handle utils.ErrSkipped in your caller — it signals skip, not fatal failure.
  4. Check vfs.IsSpecialName for the list of reserved names and avoid creating such files upstream.

Example fix

// before
err := store.Put(ctx, key, reader) // key == ".stats" -> error
// after
if vfs.IsSpecialName(key) {
    return utils.ErrSkipped // skip intentionally
}
err := store.Put(ctx, key, reader)
Defensive patterns

Strategy: validation

Validate before calling

if vfs.IsSpecialName(key) {
    return utils.ErrSkipped // skip before calling Put
}

Try / catch

err := store.Put(ctx, key, reader)
if errors.Is(err, utils.ErrSkipped) {
    log.Infof("skipped reserved file %s", key)
    return nil
}

Prevention

When it happens

Trigger: objectStorage.Put(key, ...) — directly or via UploadPartStream — where key is or lives under a reserved internal name (e.g. putting an object literally named '.stats' or '.accesslog' via the S3 gateway or `juicefs sync` into a jfs target).

Common situations: Syncing a directory that contains files named .accesslog/.stats/.config into a jfs:// target; an S3 client of the gateway PUTting an object with a reserved name; listing a JuiceFS mount recursively and re-uploading its control files.

Understand the failure class

Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.

Related errors


AI-assisted analysis of juicedata/juicefs@c9a67b23e8 (2026-09-06). Data as JSON: /api/errors/3c0ee2265ba00274. Report an issue: GitHub.