juicedata/juicefs · error
readdir %s
Error message
readdir %s
What it means
readDirSorted in nfs.go wraps a failure from n.target.ReadDirPlus(dirname) with `readdir %s`. It means listing a directory (prefix) on the NFS target failed while serving List. The wrapped underlying error distinguishes ENOENT, ENOTDIR, EACCES, and NFS protocol/mount failures.
Source
Thrown at pkg/object/nfs.go:271
}
if fi.IsDir() {
if key != "" && !strings.HasSuffix(key, "/") {
ff.key += "/"
}
ff.size = 0
}
return ff
}
func (n *nfsStore) readDirSorted(ctx context.Context, dir string, followLink bool) ([]*nfsEntry, error) {
o, err := n.Head(ctx, strings.TrimSuffix(dir, "/"))
if err != nil {
return nil, err
}
dirname := o.Key()
entries, err := n.target.ReadDirPlus(dirname)
if err != nil {
return nil, errors.Wrapf(err, "readdir %s", dirname)
}
nfsEntries := make([]*nfsEntry, 0, len(entries))
for _, e := range entries {
isSymlink := e.Attr.Attr.Type == nfs.NF3Lnk
if e.IsDir() {
nfsEntries = append(nfsEntries, &nfsEntry{e, e.Name() + dirSuffix, nil, false})
} else if isSymlink && followLink {
// follow symlink
src, err := n.Readlink(path.Join(dirname, e.Name()))
if err != nil {
nfsEntries = append(nfsEntries, &nfsEntry{e, e.Name(), nil, true})
logger.Errorf("readlink %s: %s", e.Name(), err)
continue
}
srcPath := path.Clean(path.Join(dirname, src))
fi, _, err := n.target.Lookup(srcPath)
if err != nil {
nfsEntries = append(nfsEntries, &nfsEntry{e, e.Name(), nil, true})View on GitHub (pinned to c9a67b23e8)
Solutions
- Verify the directory exists on the NFS export for the given prefix (or accept the missing-prefix case in your sync logic)
- Ensure the key path is a directory, not a file (trailing '/' semantics)
- Check directory read/execute permissions for the client user
- Remount or health-check the NFS export if the error is a stale-handle/connection failure
Example fix
// before
for _, it := range mustList(nfsStore, "data/2024/missing/") {}
// after
its, err := nfsStore.List(ctx, "data/2024/missing/", "")
if err != nil { log.Warnf("skip missing prefix: %v", err); return } Defensive patterns
Strategy: try-catch
Validate before calling
if fi, err := os.Stat(dirname); err != nil || !fi.IsDir() { return errSkipPrefix } Try / catch
it, err := store.List(ctx, prefix, "/")
if err != nil {
if errors.Is(err, os.ErrNotExist) { return nil } // treat missing prefix as empty
return err
} Prevention
- Treat missing prefixes as empty listings in sync/list callers
- Verify the prefix maps to a directory under the configured export root
- Ensure directory read+execute permissions for the client user
- Monitor and remount stale NFS connections before large listings
When it happens
Trigger: Calling List with a prefix whose directory does not exist on the export, the key resolves to a regular file (ENOTDIR), read permission is denied, or the NFS connection/mount fails during ReadDirPlus.
Common situations: Listing a prefix after its directory was deleted, wrong export root configured so the prefix maps outside the tree, permission changes on directories, or stale NFS mounts after network/server disruption.
Related errors
- list should return 2 keys, but got %d
- first key should be empty string, but got %s
- first object size should be 0, but got %d
- first key should be test, but got %s
- size of first key shold be 5, but got %v
AI-assisted analysis of juicedata/juicefs@c9a67b23e8 (2026-09-06).
Data as JSON: /api/errors/df7e5498acb71c21.
Report an issue: GitHub.