Budibase/budibase · error

Unable to remove top level directory - some skeleton files a

Error message

Unable to remove top level directory - some skeleton files already exist.

What it means

moveDirectory relocates the extracted skeleton contents from a temp directory to the target plugin directory. Before renaming, it checks that none of the top-level files already exist at the destination; any collision aborts with this error to avoid overwriting user files.

Source

Thrown at packages/cli/src/utils.ts:91

  return result
}

export function progressBar(total: number) {
  const bar = new progress.SingleBar({}, progress.Presets.shades_classic)
  bar.start(total, 0)
  return bar
}

export function checkSlashesInUrl(url: string) {
  return url.replace(/(https?:\/\/)|(\/)+/g, "$1$2")
}

export function moveDirectory(oldPath: string, newPath: string) {
  const files = fs.readdirSync(oldPath)
  // check any file exists already
  for (let file of files) {
    if (fs.existsSync(join(newPath, file))) {
      throw new Error(
        "Unable to remove top level directory - some skeleton files already exist."
      )
    }
  }
  for (let file of files) {
    fs.renameSync(join(oldPath, file), join(newPath, file))
  }
  fs.rmdirSync(oldPath)
}

export function capitaliseFirstLetter(str: string) {
  return str.charAt(0).toUpperCase() + str.slice(1)
}

export function stringifyToDotEnv(json: Record<string, string | number>) {
  let str = ""
  for (let [key, value] of Object.entries(json)) {
    str += `${key}=${value}\n`

View on GitHub (pinned to a81a902e9a)

Solutions

  1. Remove or move aside the conflicting files listed by `ls` in the target directory, then re-run
  2. Delete the partial plugin directory and run init again in a clean folder
  3. Initialize into a new empty directory instead of an existing one

Example fix

// before
my-plugin/ package.json   (leftover from failed run)
// Error: Unable to remove top level directory - some skeleton files already exist.
// after
rm -rf my-plugin && budibase-plugins init component my-plugin
Defensive patterns

Strategy: validation

Validate before calling

import fs from "fs"
import { join } from "path"
const collisions = fs.readdirSync(tmpExtractDir).filter(f => fs.existsSync(join(targetDir, f)))
if (collisions.length) throw new Error(`Conflicting files exist: ${collisions.join(", ")}`)

Try / catch

try {
  initPlugin(targetDir)
} catch (err) {
  if ((err as Error).message.includes("already exist")) {
    // clean or empty the target directory and re-run init
  } else throw err
}

Prevention

When it happens

Trigger: Running the init/skeleton command into a directory where at least one file with the same name as a skeleton top-level file already exists (fs.existsSync(join(newPath, file)) is true for any file).

Common situations: Re-running init in a partially created plugin after a previous failed run; initializing into a non-empty existing folder; leftover files from a crashed move; a stale package.json already present.

Related errors


AI-assisted analysis of Budibase/budibase@a81a902e9a (2026-08-29). Data as JSON: /api/errors/a01c78dd09d4efb3. Report an issue: GitHub.