#7502·juicefs

Replacing file link with another file via `rename` results in `Input/output error` if link with the same path was unlinked before

Author: Slava0135Created Sep 3, 2026Updated Sep 3, 2026
Labelskind/bug

What happened:

Hello I am running some tests for different filesystems, including juicefs. There seems to be a following issue when using FUSE (POSIX) interface and SQLite metadata storage:

  1. Create an empty file file1.
  2. Create (hard) link from file1 at link.
  3. Unlink link.
  4. Create an empty file file2.
  5. Create (hard) link from file1 at link again.
  6. Try to rename file2 to link.

Last operation fails with Input/output error.

Mount log reports internal error (file locations from 1.5.0-dev+2026-09-03.f2f31b6f):

log
2026/09/03 07:52:57.157083 juicefs[1495] <ERROR>: error: UNIQUE constraint failed: jfs_edge.parent, jfs_edge.name
goroutine 368 [running]:
runtime/debug.Stack()
        /usr/lib/go-1.26/src/runtime/debug/stack.go:26 +0x5e
github.com/juicedata/juicefs/pkg/meta.errno({0x50a4f00, 0x3eb4c02bd770})
        /root/juicefs-git/pkg/meta/utils.go:157 +0x16e
github.com/juicedata/juicefs/pkg/meta.(*dbMeta).doRename(0x3eb4bf766ac0, {0x512b240, 0x3eb4bf9a9040}, 0x1, {0x3eb4c01d8b14, 0x5}, 0x1, {0x3eb4c01d8b1c, 0x4}, 0x0, ...)
        /root/juicefs-git/pkg/meta/sql.go:2663 +0x448
github.com/juicedata/juicefs/pkg/meta.(*baseMeta).Rename(0x3eb4bf369408, {0x512b240, 0x3eb4bf9a9040}, 0x1, {0x3eb4c01d8b14, 0x5}, 0x1, {0x3eb4c01d8b1c, 0x4}, 0x0, ...)
        /root/juicefs-git/pkg/meta/base.go:1965 +0x90d
github.com/juicedata/juicefs/pkg/vfs.(*VFS).Rename(0x3eb4c02c1360, {0x512de60, 0x3eb4bf9a9040}, 0x1, {0x3eb4c01d8b14, 0x5}, 0x1, {0x3eb4c01d8b1c, 0x4}, 0x0)
        /root/juicefs-git/pkg/vfs/vfs.go:374 +0x2fc
github.com/juicedata/juicefs/pkg/fuse.(*fileSystem).Rename(0x3eb4c056c0a0, 0x4a639d?, 0x3eb4bf7c86c0, {0x3eb4c01d8b14, 0x5}, {0x3eb4c01d8b1c, 0x4})
        /root/juicefs-git/pkg/fuse/fuse.go:165 +0xd1
github.com/hanwen/go-fuse/v2/fuse.doRename(0x3eb4c02f2f00, 0x3eb4bf71a488)
        /root/go/pkg/mod/github.com/juicedata/go-fuse/[email protected]/fuse/opcode.go:487 +0xf4
github.com/hanwen/go-fuse/v2/fuse.init.1.func1(0x1a00000068?, 0x2?)
        /root/go/pkg/mod/github.com/juicedata/go-fuse/[email protected]/fuse/opcode.go:810 +0x43
github.com/hanwen/go-fuse/v2/fuse.(*Server).handleRequest(0x3eb4c02f2f00, 0x3eb4bf71a488)
        /root/go/pkg/mod/github.com/juicedata/go-fuse/[email protected]/fuse/server.go:821 +0x2f1
github.com/hanwen/go-fuse/v2/fuse.(*Server).loop(0x3eb4c02f2f00, 0x1)
        /root/go/pkg/mod/github.com/juicedata/go-fuse/[email protected]/fuse/server.go:794 +0x110
created by github.com/hanwen/go-fuse/v2/fuse.(*Server).readRequest in goroutine 1
        /root/go/pkg/mod/github.com/juicedata/go-fuse/[email protected]/fuse/server.go:451 +0x668 [[email protected]:157]

What you expected to happen:

Last operation is expected to finish successfully.

How to reproduce it (as minimally and precisely as possible):

c
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>

int main() {
  int status;

  status = creat("file1", S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);
  printf("CREAT: %d\n", status);
  close(status);

  status = link("file1", "link");
  printf("LINK: %d\n", status);

  status = unlink("link");
  printf("UNLINK: %d\n", status);

  status = creat("file2", S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);
  printf("CREAT: %d\n", status);
  close(status);

  status = link("file1", "link");
  printf("LINK: %d\n", status);

  status = rename("file2", "link");
  printf("RENAME: %d (%s)\n", status, strerror(errno));
}

// ::Expected::
// CREAT: 3
// LINK: 0
// UNLINK: 0
// CREAT: 3
// LINK: 0
// RENAME: 0 (Success)

// ::Actual::
// CREAT: 3
// LINK: 0
// UNLINK: 0
// CREAT: 3
// LINK: 0
// RENAME: -1 (Input/output error)

Steps:

  • Create a new juicefs filesystem in standalone mode with SQLite metadata storage.
  • Mount the filesystem.
  • Compile the test and run it inside filesystem root.
  • Observe that last operation fails with error.

Anything else we need to know?

Full command output:

log
root@ubuntu:/# ~/juicefs-git/juicefs format sqlite3://fstest.db fstest
2026/09/03 07:49:57.899113 juicefs[1453] <INFO>: Meta address: sqlite3://fstest.db [[email protected]:655]
2026/09/03 07:49:57.900858 juicefs[1453] <INFO>: Data use file:///var/jfs/fstest/ [[email protected]:584]
2026/09/03 07:49:57.904053 juicefs[1453] <INFO>: Volume is formatted as {
  "Name": "fstest",
  "UUID": "351aef67-786f-431e-82f3-28da539acb17",
  "Storage": "file",
  "Tiers": {
    "0": {
      "ID": 0,
      "StorageClass": "",
      "Tag": ""
    }
  },
  "Bucket": "/var/jfs/",
  "BlockSize": 4096,
  "Compression": "none",
  "EncryptAlgo": "aes256gcm-rsa",
  "TrashDays": 1,
  "MetaVersion": 1,
  "MinClientVersion": "1.1.0-A",
  "DirStats": true,
  "EnableACL": false
} [[email protected]:621]
root@ubuntu:/# ~/juicefs-git/juicefs mount sqlite3://fstest.db /mnt/fstest --enable-xattr
2026/09/03 07:52:12.922152 juicefs[1486] <INFO>: Meta address: sqlite3://fstest.db [[email protected]:655]
2026/09/03 07:52:12.924108 juicefs[1486] <INFO>: Data use file:///var/jfs/fstest/ [[email protected]:619]
2026/09/03 07:52:12.955627 juicefs[1495] <INFO>: Meta address: sqlite3://fstest.db [[email protected]:655]
2026/09/03 07:52:12.957249 juicefs[1495] <INFO>: Data use file:///var/jfs/fstest/ [[email protected]:619]
2026/09/03 07:52:12.957289 juicefs[1495] <INFO>: JuiceFS version 1.5.0-dev+2026-09-03.f2f31b6f [[email protected]:662]
2026/09/03 07:52:12.957931 juicefs[1495] <INFO>: Disk cache (/var/jfsCache/351aef67-786f-431e-82f3-28da539acb17/): used ratio - [space 80.7%, inode 17.5%] [newDiskCache@disk_cache.go:145]
2026/09/03 07:52:12.958008 juicefs[1495] <INFO>: Adjusted cache capacity based on freeratio: from 107374182400 to 13886465680 bytes [setLimitByFreeRatio@disk_cache.go:168]
2026/09/03 07:52:12.958081 juicefs[1495] <INFO>: Adjusted max items based on freeratio: from 0 to 1693439 items [setLimitByFreeRatio@disk_cache.go:182]
2026/09/03 07:52:12.960283 juicefs[1495] <INFO>: Create session 1 OK with version: 1.5.0-dev+2026-09-03.f2f31b6f [[email protected]:805]
2026/09/03 07:52:12.961027 juicefs[1495] <INFO>: Prometheus metrics listening on "127.0.0.1:9567" [[email protected]:137]
2026/09/03 07:52:12.961624 juicefs[1495] <INFO>: Mounting volume fstest at "/mnt/fstest" ... [mountMain@mount_unix.go:1167]
2026-09-03 07:52:13.028840 I | Unimplemented opcode POLL
2026/09/03 07:52:13.029469 juicefs[1486] <INFO>: watching "/mnt/fstest", pid 1495 [watchdog@mount_unix.go:237]
2026/09/03 07:52:13.426108 juicefs[1486] <INFO>: OK, fstest is ready at "/mnt/fstest" [checkMountpoint@mount_unix.go:327]
2026/09/03 07:52:57.157083 juicefs[1495] <ERROR>: error: UNIQUE constraint failed: jfs_edge.parent, jfs_edge.name
goroutine 368 [running]:
runtime/debug.Stack()
        /usr/lib/go-1.26/src/runtime/debug/stack.go:26 +0x5e
github.com/juicedata/juicefs/pkg/meta.errno({0x50a4f00, 0x3eb4c02bd770})
        /root/juicefs-git/pkg/meta/utils.go:157 +0x16e
github.com/juicedata/juicefs/pkg/meta.(*dbMeta).doRename(0x3eb4bf766ac0, {0x512b240, 0x3eb4bf9a9040}, 0x1, {0x3eb4c01d8b14, 0x5}, 0x1, {0x3eb4c01d8b1c, 0x4}, 0x0, ...)
        /root/juicefs-git/pkg/meta/sql.go:2663 +0x448
github.com/juicedata/juicefs/pkg/meta.(*baseMeta).Rename(0x3eb4bf369408, {0x512b240, 0x3eb4bf9a9040}, 0x1, {0x3eb4c01d8b14, 0x5}, 0x1, {0x3eb4c01d8b1c, 0x4}, 0x0, ...)
        /root/juicefs-git/pkg/meta/base.go:1965 +0x90d
github.com/juicedata/juicefs/pkg/vfs.(*VFS).Rename(0x3eb4c02c1360, {0x512de60, 0x3eb4bf9a9040}, 0x1, {0x3eb4c01d8b14, 0x5}, 0x1, {0x3eb4c01d8b1c, 0x4}, 0x0)
        /root/juicefs-git/pkg/vfs/vfs.go:374 +0x2fc
github.com/juicedata/juicefs/pkg/fuse.(*fileSystem).Rename(0x3eb4c056c0a0, 0x4a639d?, 0x3eb4bf7c86c0, {0x3eb4c01d8b14, 0x5}, {0x3eb4c01d8b1c, 0x4})
        /root/juicefs-git/pkg/fuse/fuse.go:165 +0xd1
github.com/hanwen/go-fuse/v2/fuse.doRename(0x3eb4c02f2f00, 0x3eb4bf71a488)
        /root/go/pkg/mod/github.com/juicedata/go-fuse/[email protected]/fuse/opcode.go:487 +0xf4
github.com/hanwen/go-fuse/v2/fuse.init.1.func1(0x1a00000068?, 0x2?)
        /root/go/pkg/mod/github.com/juicedata/go-fuse/[email protected]/fuse/opcode.go:810 +0x43
github.com/hanwen/go-fuse/v2/fuse.(*Server).handleRequest(0x3eb4c02f2f00, 0x3eb4bf71a488)
        /root/go/pkg/mod/github.com/juicedata/go-fuse/[email protected]/fuse/server.go:821 +0x2f1
github.com/hanwen/go-fuse/v2/fuse.(*Server).loop(0x3eb4c02f2f00, 0x1)
        /root/go/pkg/mod/github.com/juicedata/go-fuse/[email protected]/fuse/server.go:794 +0x110
created by github.com/hanwen/go-fuse/v2/fuse.(*Server).readRequest in goroutine 1
        /root/go/pkg/mod/github.com/juicedata/go-fuse/[email protected]/fuse/server.go:451 +0x668 [[email protected]:157]

Environment:

  • JuiceFS version (use juicefs --version) or Hadoop Java SDK version: 1.4.1+2026-07-30.0b90c7d & 1.5.0-dev+2026-09-03.f2f31b6f
  • Cloud provider or hardware configuration running JuiceFS: None
  • OS (e.g cat /etc/os-release): Ubuntu 26.04.1 LTS
  • Kernel (e.g. uname -a): Linux ubuntu 7.0.0-30-generic #30-Ubuntu SMP PREEMPT_DYNAMIC Fri Jul 31 18:22:54 UTC 2026 x86_64 GNU/Linux
  • Object storage (cloud provider and region, or self maintained): Self
  • Metadata engine info (version, cloud provider managed or self maintained): SQLite
  • Network connectivity (JuiceFS to metadata engine, JuiceFS to object storage): None
  • Others: None