Skip to content

os.homedir() uses process-start HOME snapshot instead of current process.env.HOME #29244

@CorticalCode

Description

@CorticalCode

What version of Bun is running?

1.3.12+700fc117a

What platform is your computer?

Darwin 25.4.0 arm64 arm

What steps can reproduce the bug?

os.homedir() returns a stale value after process.env.HOME is mutated at runtime. The value is snapshotted at process start — even mutating HOME before require('node:os') and before the first os.homedir() call has no effect.

const os = require('node:os');

// 1. Baseline
console.log('Before:', os.homedir());

// 2. Mutate HOME at runtime
process.env.HOME = '/tmp/test-home';
console.log('After:', os.homedir());
console.log('process.env.HOME:', process.env.HOME);

A stronger variant — mutate HOME before require and before the first call:

// Mutate HOME before require and before first os.homedir() call
process.env.HOME = '/tmp/before-require';
const os = require('node:os');
console.log('os.homedir():', os.homedir());
console.log('process.env.HOME:', process.env.HOME);

What is the expected behavior?

Node.js (v25.9.0):

Before: /Users/username
After: /tmp/test-home
process.env.HOME: /tmp/test-home

And for the "before require" variant:

os.homedir(): /tmp/before-require
process.env.HOME: /tmp/before-require

Per the Node.js docs: "On POSIX, it uses the $HOME environment variable if defined."

What do you see instead?

Bun (1.3.12):

Before: /Users/username
After: /Users/username
process.env.HOME: /tmp/test-home

And for the "before require" variant:

os.homedir(): /Users/username
process.env.HOME: /tmp/before-require

os.homedir() returns the original home directory regardless of process.env.HOME mutations — even when HOME is changed before require('node:os') is called.

Additional information

This is an internal inconsistency in Bun's os module. os.tmpdir() correctly reflects runtime TMPDIR changes, while os.homedir() does not reflect runtime HOME changes:

const os = require('node:os');

// tmpdir: reflects runtime change
process.env.TMPDIR = '/tmp/custom';
console.log('tmpdir:', os.tmpdir());  // → /tmp/custom ✓

// homedir: does NOT reflect runtime change
process.env.HOME = '/tmp/custom';
console.log('homedir:', os.homedir());  // → /Users/username ✗

Note: os.userInfo().homedir does not reflect HOME changes in either runtime — that reads from the system passwd database, which is correct behavior. The issue is specifically with os.homedir().

Impact: Test suites commonly redirect HOME to a temp directory to isolate config files and caches. Libraries that resolve paths via os.homedir() will write to the real home directory instead of the test fixture, causing subtle test pollution.

Workaround: Read process.env.HOME directly instead of calling os.homedir().

Related: #29237 / #29239 — similar stale-env-snapshot pattern in child_process sync variants, now fixed.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions