Skip to content

wgc router plugin init fails with EXDEV error on cross-filesystem operations #2455

@Colin23

Description

@Colin23

Component(s)

cli

Component version

N/A (this bug affects the CLI tool, not the router)

wgc version

0.103.4

controlplane version

cloud

router version

N/A (this bug affects the CLI tool, not the router)

What happened?

Description

The wgc router plugin init command fails with an EXDEV: cross-device link not permitted error when attempting to scaffold a new plugin. This occurs because the code uses fs.rename() to move the temporary directory from /tmp to the target location, but rename() cannot move files across different filesystems.

Steps to Reproduce

Run wgc router plugin init my-plugin on a Linux system where /tmp is on a different filesystem than the home directory (e.g., /tmp is tmpfs or a separate partition)

My current setup:

Filesystem Size Used Avail Use% Mounted on
tmpfs 3,1G 3,0M 3,1G 1% /run
/dev/dm-0 905G 453G 406G 53% /
tmpfs 16G 97M 15G 1% /dev/shm
tmpfs 5,0M 24K 5,0M 1% /run/lock
efivarfs 248K 128K 116K 53% /sys/firmware/efi/efivars
tmpfs 16G 86M 15G 1% /tmp
/dev/nvme0n1p1 300M 11M 289M 4% /boot/efi
tmpfs 3,1G 2,8M 3,1G 1% /run/user/341205717

The command will fail with the error:
EXDEV: cross-device link not permitted, rename '/tmp/cosmo-plugin-<uuid>' -> '/home/<user>/path/to/my-plugin'

Expected Result

The plugin should be successfully scaffolded regardless of filesystem boundaries. The tool should handle cross-filesystem moves gracefully.

Actual Result

The command fails with an EXDEV error. The temporary directory is created in /tmp but cannot be moved to the target location.
Example output:

[●] Plugin scaffolding
 │
 ├────────── name: MyPlugin
 ├───────── state: failed
 └───────── error: EXDEV: cross-device link not permitted, rename '/tmp/cosmo-plugin-79bd515a-ebc6-457c-b554-1553d0675778' -> '/home/cmoerbe/development/personal/colin/graphql-cosmo-playground/my-plugin'

Root cause

In packages/wgc/src/commands/router/commands/plugin/commands/init.ts at line 114, the code uses:

await rename(tempDir, pluginDir);

The fs.rename() function uses the system's rename() call, which cannot operate across filesystem boundaries.

Suggested fix

Replace the rename() call with a fallback mechanism or use a different approach all together. E.g.

try {
  await rename(tempDir, pluginDir);
} catch (error) {
  if (error.code === 'EXDEV') {
    // Cross-device link, fall back to copy + remove
    await cp(tempDir, pluginDir, { recursive: true });
    await rm(tempDir, { recursive: true, force: true });
  } else {
    throw error;
  }
}

I haven't tested if this code would actually solve the problem. Be cautious about this recommendation!

Environment information

Environment

OS: KDE neon User Edition x86_64, #.37~24.04.1-Ubuntu, 6.14.0-37-generic
Package Manager: npm

Router configuration

N/A (this bug affects the CLI tool, not the router)

Router execution config

N/A (this bug affects the CLI tool, not the router)

Log output

[●] Plugin scaffolding
 │
 ├────────── name: PokemonPlugin
 ├───────── state: failed
 └───────── error: EXDEV: cross-device link not permitted, rename '/tmp/cosmo-plugin-79bd515a-ebc6-457c-b554-1553d0675778' -> '/home/cmoerbe/development/personal/colin/graphql-cosmo-playground/my-plugin'

Additional context

No response

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workinginternally-reviewedThe issue has been reviewed internally.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions