This error occurs when Node.js receives a malformed or unrecognized timezone string from the TZ environment variable. The TZ variable expects valid IANA timezone identifiers (like "America/New_York" or "Europe/London") or POSIX timezone strings, but receives an invalid or misspelled value instead. This causes date and time operations to fail or behave unpredictably.
Node.js uses the TZ environment variable to set the system timezone for all date and time operations. When this variable is set, Node.js validates it against the IANA Time Zone Database or POSIX timezone format standards. If the TZ value doesn't match any valid timezone identifier, Node.js raises an error indicating the timezone string is invalid or malformed. This might happen due to typos, incorrect path formats, custom strings that aren't recognized, or values that were valid in a different system. The error prevents proper timezone conversion, which affects functions like `Date.toString()`, `toLocaleString()`, and any timezone-aware libraries. The application either crashes or silently falls back to UTC, causing incorrect time display or calculations in logging, scheduling, and business logic.
First, check what value is actually set for the TZ environment variable:
# On Linux/macOS
echo $TZ
# Check in Node.js
node -e "console.log(process.env.TZ)"
# Inside a running Node.js app
console.log('TZ:', process.env.TZ);If it's empty, that's the issue. If it has a value, check it carefully for typos or incorrect formatting.
Node.js expects timezone identifiers from the IANA Time Zone Database. Common valid formats:
# Correct IANA timezone formats
TZ='America/New_York' node app.js
TZ='Europe/London' node app.js
TZ='Asia/Tokyo' node app.js
TZ='Australia/Sydney' node app.js
TZ='UTC' node app.js
TZ='Etc/UTC' node app.js
# Case-sensitive - exact capitalization matters
# America/new_york is WRONG
# america/new_york is WRONG
# America/New_York is CORRECTTimezone identifiers are case-sensitive. The first part (continent/region) uses proper capitalization. Use the complete list from the IANA Time Zone Database: https://en.wikipedia.org/wiki/List_of_tz_database_time_zones
The TZ environment variable should be set before any date/time operations occur in your application:
// Set at application start, before importing other modules
process.env.TZ = 'America/New_York';
// Then import and use date functions
const app = require('./app');
// Verify it's applied
const now = new Date();
console.log('Current time in', process.env.TZ, ':', now.toString());
console.log('Timezone offset:', now.getTimezoneOffset());If you're using .env files, load them very early:
// First thing in your app
require('dotenv').config();
process.env.TZ = process.env.TZ || 'UTC';
// Then continue with rest of app
const express = require('express');If using Docker, set the TZ environment variable in your Dockerfile or docker-compose.yml:
# Dockerfile
FROM node:20-alpine
# Set valid timezone
ENV TZ=America/New_York
WORKDIR /app
COPY . .
RUN npm install
CMD ["node", "app.js"]For docker-compose:
version: '3'
services:
app:
build: .
environment:
- TZ=America/New_York # Valid IANA timezoneOn Railway or other platforms, add the TZ environment variable in the dashboard with a valid value like America/New_York, not a file path.
A common mistake is trying to use a file path as the timezone value:
# WRONG - this causes the error
export TZ=/etc/localtime
node app.js
# WRONG - this also fails
export TZ=/usr/share/zoneinfo/America/New_York
node app.js
# CORRECT - use the timezone identifier directly
export TZ=America/New_York
node app.jsOn some Unix systems, you can reference the timezone file indirectly:
# This might work on Linux (but not all systems)
TZ=:/etc/localtime node app.jsBut the reliable, cross-platform way is to use the IANA identifier directly.
Add validation to catch invalid timezones before they cause problems:
// List of commonly used valid timezones
const VALID_TIMEZONES = [
'UTC',
'America/New_York',
'America/Chicago',
'America/Denver',
'America/Los_Angeles',
'Europe/London',
'Europe/Paris',
'Europe/Berlin',
'Asia/Tokyo',
'Asia/Shanghai',
'Australia/Sydney',
];
function validateTimezone(tz) {
if (!tz) return 'UTC'; // Default fallback
// Simple check - a real implementation should validate against the full IANA database
if (VALID_TIMEZONES.includes(tz)) {
return tz;
}
console.warn(`Invalid timezone "${tz}", using UTC instead`);
return 'UTC';
}
// At startup
const validTZ = validateTimezone(process.env.TZ);
process.env.TZ = validTZ;
console.log(`Timezone set to: ${validTZ}`);For robust validation, use a library that knows all IANA timezones:
// Using moment-timezone (if available in your project)
const moment = require('moment-timezone');
const tz = process.env.TZ;
if (!moment.tz.zone(tz)) {
console.error(`Invalid timezone: ${tz}`);
process.env.TZ = 'UTC';
}Add tests to ensure timezone handling works correctly:
// test/timezone.test.js
describe('Timezone handling', () => {
test('TZ environment variable is valid', () => {
const tz = process.env.TZ;
expect(tz).toBeDefined();
// Attempt to use a date with the TZ
const now = new Date();
const formatted = now.toLocaleString('en-US', {
timeZone: tz
});
// If this doesn't throw, timezone is valid
expect(formatted).toBeTruthy();
});
test('dates display correct timezone', () => {
process.env.TZ = 'America/New_York';
const now = new Date('2024-01-15T12:00:00Z');
const estTime = now.toLocaleString('en-US', {
timeZone: 'America/New_York'
});
// EST is UTC-5 in January
expect(estTime).toContain('7:00:00 AM');
});
});In your GitHub Actions or CI pipeline:
# .github/workflows/test.yml
jobs:
test:
runs-on: ubuntu-latest
env:
TZ: America/New_York
steps:
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
with:
node-version: '20'
- run: npm testIANA vs POSIX Timezone Strings
Node.js supports both IANA and POSIX timezone formats, but IANA is preferred:
- IANA (recommended): Simple, human-readable names like "America/New_York", "Europe/London"
- POSIX (advanced): Complex format like "EST5EDT,M3.2.0,M11.1.0" (difficult to get right)
POSIX strings are error-prone. Unless you have a specific reason, use IANA identifiers.
Platform Differences
- Linux/macOS: Full IANA timezone support via the system's timezone database
- Windows: More limited timezone support; stick to standard IANA names
- Docker on Windows: Additional complexity with timezone mapping between Windows host and Linux container
If your app runs on multiple platforms, test with the same timezone across all of them.
Daylight Saving Time (DST)
IANA timezone identifiers automatically handle DST transitions. POSIX strings require manual DST rule specification, which is why they're error-prone.
// With IANA - DST handled automatically
process.env.TZ = 'America/New_York';
const now = new Date('2024-01-15'); // Winter, EST (UTC-5)
const summer = new Date('2024-07-15'); // Summer, EDT (UTC-4)
// Timezone offsets adjust automatically
// With POSIX - you must specify DST rules manually
// Not recommended unless necessaryChecking Available Timezones
To see all valid timezones on your system:
# Linux/macOS - list timezone files
ls /usr/share/zoneinfo/
# Or check the IANA database online
# https://en.wikipedia.org/wiki/List_of_tz_database_time_zonesTimezone in Docker Alpine
Alpine Linux containers have a minimal timezone database. Install the full one if needed:
FROM node:20-alpine
# Install full timezone database
RUN apk add --no-cache tzdata
ENV TZ=America/New_York
WORKDIR /app
COPY . .
RUN npm install
CMD ["node", "app.js"]Without tzdata, Alpine may not recognize all IANA timezone identifiers.
Testing Timezone Behavior
// Quick timezone test
function testTimezone(tz) {
const oldTZ = process.env.TZ;
process.env.TZ = tz;
const now = new Date();
const formatted = now.toString();
process.env.TZ = oldTZ;
return formatted;
}
console.log('New York:', testTimezone('America/New_York'));
console.log('London:', testTimezone('Europe/London'));
console.log('Tokyo:', testTimezone('Asia/Tokyo'));Error: Listener already called (once event already fired)
EventEmitter listener already called with once()
Error: EACCES: permission denied, open '/root/file.txt'
EACCES: permission denied
Error: Invalid encoding specified (stream encoding not supported)
How to fix Invalid encoding error in Node.js readable streams
Error: EINVAL: invalid argument, open
EINVAL: invalid argument, open
TypeError: readableLength must be a positive integer (stream config)
TypeError: readableLength must be a positive integer in Node.js streams