How to fix Error: Invalid timezone string (TZ environment variable malformed) in Node.js

Node.jsINTERMEDIATEMEDIUMUpdated Dec 9, 2025ยท 121 views

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.

Quick fix

Fixes ERR_INVALID_TZ_STRING

# 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);
  1. Verify the TZ environment variable is set correctly
  2. Use valid IANA timezone identifiers
  3. Set TZ before date operations
  4. Check your Docker or deployment configuration
node.js โ€” error
# 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);
Error: Invalid timezone string (TZ environment variable malformed)

What this error means

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.

Typical symptoms

  • Error thrown: "Invalid timezone string" when Node.js starts
  • Date and time operations return incorrect times despite TZ being set
  • Application silently falls back to UTC timezone
  • Log timestamps show wrong time or timezone offset
  • Scheduled tasks (cron jobs) execute at unexpected times
  • Docker containers fail to start with timezone configuration errors
  • Cross-timezone testing fails because TZ value is rejected

Common causes

  1. Typo in timezone name (e.g., "Amercia/New_York" instead of "America/New_York")
  2. Using a file path instead of timezone identifier (e.g., "/etc/localtime" instead of just the timezone)
  3. Using lowercase or incorrectly cased timezone (e.g., "america/new_york" instead of "America/New_York")
  4. Using invalid timezone format (e.g., "EST5EDT" without proper POSIX syntax)
  5. Timezone identifier not in IANA Time Zone Database
  6. Environment variable loaded incorrectly or from wrong source
  7. Different timezone database between development and production environments
  8. Platform-specific timezone string that doesn't work cross-platform (especially Windows)

How to fix "Error: Invalid timezone string (TZ environment variable malformed)"

1Verify the TZ environment variable is set correctly

First, check what value is actually set for the TZ environment variable:

bash
# 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.

2Use valid IANA timezone identifiers

Node.js expects timezone identifiers from the IANA Time Zone Database. Common valid formats:

bash
# 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 CORRECT

Timezone 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

3Set TZ before date operations

The TZ environment variable should be set before any date/time operations occur in your application:

javascript
// 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:

javascript
// 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');
4Check your Docker or deployment configuration

If using Docker, set the TZ environment variable in your Dockerfile or docker-compose.yml:

dockerfile
# 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:

yaml
version: '3'
services:
  app:
    build: .
    environment:
      - TZ=America/New_York  # Valid IANA timezone

On Railway or other platforms, add the TZ environment variable in the dashboard with a valid value like America/New_York, not a file path.

5Don't use file paths for timezone

A common mistake is trying to use a file path as the timezone value:

bash
# 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.js

On some Unix systems, you can reference the timezone file indirectly:

bash
# This might work on Linux (but not all systems)
TZ=:/etc/localtime node app.js

But the reliable, cross-platform way is to use the IANA identifier directly.

6Validate and provide a fallback

Add validation to catch invalid timezones before they cause problems:

javascript
// 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:

javascript
// 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';
}
7Test timezone changes in your CI/CD pipeline

Add tests to ensure timezone handling works correctly:

javascript
// 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:

yaml
# .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 test

Advanced notes

IANA 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.

javascript
// 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 necessary

Checking Available Timezones

To see all valid timezones on your system:

bash
# 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_zones

Timezone in Docker Alpine

Alpine Linux containers have a minimal timezone database. Install the full one if needed:

dockerfile
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

javascript
// 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'));

Frequently asked questions

What does "ERR_INVALID_TZ_STRING" mean?
js uses the TZ environment variable to set the system timezone for all date and time operations. js validates it against the IANA Time Zone Database or POSIX timezone format standards. js raises an error indicating the timezone string is invalid or malformed.
How do I fix "ERR_INVALID_TZ_STRING"?
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.
What causes "ERR_INVALID_TZ_STRING"?
Typo in timezone name (e.g., "Amercia/New_York" instead of "America/New_York") Using a file path instead of timezone identifier (e.g., "/etc/localtime" instead of just the timezone) Using lowercase or incorrectly cased timezone (e.g., "america/new_york" instead of "America/New_York")
Is the "ERR_INVALID_TZ_STRING" error serious?
It is a medium-severity error โ€” more of a blocker than a risk. The steps above resolve it.

Official resources & further reading