vitejs/vite · error · Error
"local" cannot be used as a mode name because it conflicts w
Error message
"local" cannot be used as a mode name because it conflicts with the .local postfix for .env files.
What it means
`loadEnv` rejects the literal mode string `"local"` because Vite reserves the `.local` suffix for git-ignored override files (`.env.local`, `.env.<mode>.local`). Using `local` as a mode would collide: `.env.local` would be ambiguous between the mode file and the always-local override, and `getEnvFilesForMode` already lists `.env.local` unconditionally. The guard at env.ts:41 prevents the ambiguity.
Source
Thrown at packages/vite/src/node/env.ts:42
}
return []
}
/**
* Load `.env` files within the `envDir` and merge them with the matching
* variables already present in `process.env`.
*/
export function loadEnv(
mode: string,
envDir: string | false,
prefixes: string | string[] = 'VITE_',
): Record<string, string> {
const start = performance.now()
const getTime = () => `${(performance.now() - start).toFixed(2)}ms`
if (mode === 'local') {
throw new Error(
`"local" cannot be used as a mode name because it conflicts with ` +
`the .local postfix for .env files.`,
)
}
prefixes = arraify(prefixes)
const env: Record<string, string> = {}
const envFiles = getEnvFilesForMode(mode, envDir)
debug?.(`loading env files: %O`, envFiles)
const parsed = Object.fromEntries(
envFiles.flatMap((filePath) => {
const stat = tryStatSync(filePath)
// Support FIFOs (named pipes) for apps like 1Password
if (!stat || (!stat.isFile() && !stat.isFIFO())) return []
const parsedEnv = parseEnv(fs.readFileSync(filePath, 'utf-8'))
return Object.entries(parsedEnv as Record<string, string>)View on GitHub (pinned to 89620f09af)
Solutions
- Pick a non-reserved mode name such as `development`, `dev-local`, `localhost`, or `local-dev`.
- If you wanted machine-specific overrides, keep `mode: 'development'` and put secrets in `.env.local` (which Vite loads automatically).
- Audit scripts/CI for `--mode local` and rename the mode variable.
Example fix
// before
loadEnv('local', process.cwd())
// vite build --mode local
// after
loadEnv('development', process.cwd())
// vite build --mode development Defensive patterns
Strategy: validation
Validate before calling
const RESERVED_MODES = new Set(['local'])
function assertMode(mode: string) {
if (RESERVED_MODES.has(mode)) throw new Error(`Mode '${mode}' is reserved; use 'development' or a custom name`)
} Type guard
function isValidMode(mode: string): boolean {
return mode !== 'local' && /^[a-z0-9-]+$/i.test(mode)
} Prevention
- Treat 'local' as a reserved word in your env/mode tooling.
- Use .env.local for machine overrides rather than a 'local' mode.
When it happens
Trigger: Calling `loadEnv('local', ...)` directly, running `vite build --mode local`, or programmatically starting a server/preview with `mode: 'local'`.
Common situations: Teams naming environments after machines or stages (dev/local/staging); CI configs that pass `MODE=local`; scaffold templates that default to a `local` mode name.
Related errors
- envPrefix option contains value '', which could lead unexpec
- `renderLegacyChunks` and `renderModernChunks` cannot be both
- Invalid environment name "${name}". Environment names must o
- `input` cannot contain glob characters. They are reserved, s
- Required environments configuration were stripped out in the
AI-assisted analysis of vitejs/vite@89620f09af (2026-08-03).
Data as JSON: /data/errors/4ac5cd05813f942d.json.
Report an issue: GitHub.