tailscale/tailscale · error
unable to create /userdata/init.d
Error message
unable to create /userdata/init.d
What it means
os.MkdirAll('/userdata/init.d', 0755) failed while `tailscale configure jetkvm` was preparing the directory for its S22tailscale init script. The returned error is created with errors.New and does NOT wrap the underlying os error, so the real cause (permissions, read-only filesystem, path exists as a file, disk full) is hidden from the message. This discard-the-cause pattern makes diagnosis harder than it should be.
Source
Thrown at cmd/tailscale/cli/configure-jetkvm.go:52
LongHelp: strings.TrimSpace(`
This command configures the JetKVM host to run tailscaled at boot.
`),
FlagSet: (func() *flag.FlagSet {
fs := newFlagSet("jetkvm")
return fs
})(),
}
}
func runConfigureJetKVM(ctx context.Context, args []string) error {
if len(args) > 0 {
return errors.New("unknown arguments")
}
if runtime.GOOS != "linux" || distro.Get() != distro.JetKVM {
return errors.New("only implemented on JetKVM")
}
if err := os.MkdirAll("/userdata/init.d", 0755); err != nil {
return errors.New("unable to create /userdata/init.d")
}
err := os.WriteFile("/userdata/init.d/S22tailscale", bytes.TrimLeft([]byte(`
#!/bin/sh
# /userdata/init.d/S22tailscale
# Start/stop tailscaled
case "$1" in
start)
/userdata/tailscale/tailscaled > /dev/null 2>&1 &
;;
stop)
killall tailscaled
;;
*)
echo "Usage: $0 {start|stop}"
exit 1
;;
esacView on GitHub (pinned to cfe32b8be6)
Solutions
- Re-run as root: `sudo tailscale configure jetkvm`
- Check the path manually: `ls -la /userdata/`, `mount | grep userdata`, `findmnt -no OPTIONS /userdata` (look for ro), and `df -h /userdata`
- If a regular file blocks the directory, remove or rename it, then retry
- Reproduce with `mkdir -p /userdata/init.d` to surface the real errno the CLI swallowed
Example fix
# before $ tailscale configure jetkvm error: unable to create /userdata/init.d # after (diagnose, then retry) $ sudo mkdir -p /userdata/init.d && sudo tailscale configure jetkvm
Defensive patterns
Strategy: validation
Validate before calling
# Preconditions for writing the JetKVM init script
[ "$(id -u)" = "0" ] || { echo 'run as root'; exit 1; }
mkdir -p /userdata/init.d 2>/dev/null || { echo 'cannot create /userdata/init.d'; mount | grep userdata; df -h /userdata; exit 1; }
findmnt -no OPTIONS /userdata | grep -qw ro && { echo '/userdata is read-only'; exit 1; } Try / catch
err := os.MkdirAll("/userdata/init.d", 0o755)
if err != nil {
return fmt.Errorf("creating /userdata/init.d: %w", err) // keep the cause, unlike the CLI
} Prevention
- Invoke the command via sudo on the JetKVM device
- Confirm /userdata is mounted read-write before configuring
- Reproduce filesystem errors with mkdir -p to surface the errno the CLI hides
When it happens
Trigger: Running the command as a non-root user on a JetKVM device; /userdata being mounted read-only or not mounted at all; an existing regular file named /userdata/init.d; a full userdata partition.
Common situations: Forgetting sudo on the JetKVM shell; the userdata partition not being mounted after a firmware reflash; leftover file occupying the init.d path from a previous manual install.
Related errors
- invalid path
- failed creating systemd user dir: %w
- failed extracting the new tailscale binary from %q: %w
- failed extracting the new tailscaled binary from %q: %w
- failed to remove existing file at %q: %w
AI-assisted analysis of tailscale/tailscale@cfe32b8be6 (2026-08-15).
Data as JSON: /api/errors/e8b5b76fabb7169a.
Report an issue: GitHub.