Visitar URL original
Bug: esbuild overwrites the input file despite throwing "Refusing to overwrite input file" · Issue #4484 · evanw/esbuild · GitHub
Skip to content

Bug: esbuild overwrites the input file despite throwing "Refusing to overwrite input file" #4484

Closed

Description

@noskill24

Description

When outdir points to the directory containing the entry point, esbuild throws an error:

Build failed with 1 error: error:
Refusing to overwrite input file error.

However, it still destructively overwrites the original input file with the minified version before/during throwing the error.

Reproduction

Environment

OS: Windows
esbuild version: 0.28.1

Create the following files and run node esbuild.js.

sources/test.js

function test() { console.log( 1 + 1 === 2 ); }

esbuild.js

import fs from 'fs';
import path from 'path';
import esbuild from 'esbuild';

(async function run() {
  const basePath = process.cwd();
  const sourcePath = path.resolve(basePath, "sources");
  const sourceFile = path.resolve(basePath, "sources/test.js");

  try {
    console.log("Initial source size:", fs.statSync(sourceFile).size, 'bytes');

    await esbuild.build({
      logLevel: 'silent',
      entryPoints: [ sourceFile ],
      outdir: sourcePath,
      bundle: false,
      minify: true,
      write: true,
    });

  } catch (err) {

    console.log(err.message);
    console.log("Source size after failure:", fs.statSync(sourceFile).size, 'bytes');

  }
})();

Actual Behavior

The build fails as expected, but the input file is modified anyway:

Initial source size: 47 bytes
Build failed with 1 error:
error: Refusing to overwrite input file "sources/test.js" (use "allowOverwrite: true" to allow this)
Source size after failure: 33 bytes

The content of sources/test.js becomes minified:

function test(){console.log(!0)}

Expected Behavior

esbuild should abort the write operation and leave the original input file completely untouched if allowOverwrite is not set to true.

Activity

  1. cschanhniem commented on Jun 19, 2026

    @cschanhniem

    I traced the code path. The bug is in internal/bundler/bundler.go, lines 3094–3121: the overwrite conflict check calls log.AddError with the "Refusing to overwrite" message, but does not remove the conflicting file from outputFiles. The slice continues to carry the entry whose AbsPath matches a source file.

    Then in pkg/api/api_impl.go, lines 1543–1592, the write phase iterates over all results (which still includes the conflicted entry) and calls ioutil.WriteFile on each one — including the one that maps to a source file. By the time the caller checks log.HasErrors(), the input file has already been overwritten.

    The fix: in the overwrite-check loop, when a conflict is detected, either:

    • Set a flag on the output file (e.g., Contents = nil or mark the AbsPath as excluded) so the write phase skips it, or
    • Remove the entry from outputFiles at the detection site.

    A minimal patch would be to add outputFiles[i].AbsPath = "" or similar in the conflict detection block so the write loop at line 1587 skips it. Want me to put together a PR?

  2. evanw commented on Aug 8, 2026

    @evanw
    Owner

    Thanks for reporting this. This is not great. Looks like it regressed in version 0.17.0.

  3. added a commit that references this issue on Aug 8, 2026
    c3a1e0c
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions