quasarframework/quasar · critical · Error

Refusing to remove a filesystem root as build output

Error message

Refusing to remove a filesystem root as build output

What it means

As a destructive-operation guard, getBuildArtifactsCleanTarget refuses to treat a filesystem root ('/' on POSIX, drive root on Windows) as build output. It compares both the raw resolved target and its realpath-resolved effective path (catching symlinks that point at a root) against isFilesystemRoot.

Source

Thrown at app-vite/lib/utils/remove-build-artifacts.js:72

  projectDir,
  allowOutsideProject
}) {
  if (typeof targetDir !== 'string' || targetDir.trim() === '') {
    throw new Error('Build output directory must be a non-empty path')
  }

  if (typeof projectDir !== 'string' || projectDir.trim() === '') {
    throw new Error('Project directory must be a non-empty path')
  }

  const project = resolve(projectDir)
  const effectiveProject = fse.realpathSync(project)
  const home = fse.realpathSync(resolve(homedir()))
  const target = resolve(projectDir, targetDir)
  const effectiveTarget = getEffectivePath(target)

  if (isFilesystemRoot(target) || isFilesystemRoot(effectiveTarget)) {
    throw new Error('Refusing to remove a filesystem root as build output')
  }

  if (target === home || effectiveTarget === home) {
    throw new Error(
      'Refusing to remove the user home directory as build output'
    )
  }

  if (target === project || effectiveTarget === effectiveProject) {
    throw new Error('Refusing to remove the project root as build output')
  }

  if (
    allowOutsideProject !== true &&
    isContainedPath(effectiveProject, effectiveTarget) === false
  ) {
    throw new Error(
      'Build output directory must remain inside the project. Set build.allowOutsideProjectDistDir to true to explicitly allow an external directory.'

View on GitHub (pinned to 4841521b5f)

Solutions

  1. Set distDir to a real subdirectory like 'dist' or 'build/output'
  2. Check for symlinks in the configured path ('ls -l') and repoint them away from the root
  3. Never interpolate unvalidated env vars directly into distDir; default to 'dist' when empty

Example fix

// before
distDir: process.env.DIST_DIR || '/'
// after
distDir: process.env.DIST_DIR || 'dist'
Defensive patterns

Strategy: validation

Validate before calling

const path = require('node:path')
const { parse } = require('node:path')
function isFsRoot(p) {
  const parsed = parse(path.resolve(p))
  return parsed.root === path.resolve(p) && (parsed.dir === parsed.root)
}
const target = path.resolve(projectDir, distDir)
if (isFsRoot(target)) throw new Error('dist dir resolves to filesystem root')

Try / catch

try {
  await removeBuildArtifacts(opts)
} catch (err) {
  if (err.message === 'Refusing to remove a filesystem root as build output') {
    // fix distDir config; never bypass this guard
  } else throw err
}

Prevention

When it happens

Trigger: Configuring the build output directory as '/' (or 'C:/' etc.), or as a path that resolves via symlinks to a filesystem root — e.g. distDir pointing at a symlink named /dist that actually targets /.

Common situations: Setting distDir: '/' by mistake in quasar.config.js; a symlink farm or Docker volume mount mapping the dist dir to the container root; reading an empty environment variable that collapses the path to root after resolve.

Related errors


AI-assisted analysis of quasarframework/quasar@4841521b5f (2026-08-30). Data as JSON: /api/errors/03844005c88aafae. Report an issue: GitHub.