juicedata/juicefs · warning

skip special file for jfs

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.

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.

Appendix: 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)