moment/moment · error · Error

Unknown unit ${units}

Error message

Unknown unit ${units}

What it means

Thrown by moment.duration(...).as(units) in src/lib/duration/as.js:43 when the resolved unit is not one moment can convert a duration into. normalizeUnits (src/lib/units/aliases.js:54) maps the input string to a canonical unit or returns undefined; the as() switch only handles ms/second/minute/hour/day/week and (in the month branch) month/quarter/year. Any other value falls through to the `default` and throws 'Unknown unit <units>'. Critically, calendar units like 'date', 'dayOfYear', 'weekday', 'isoWeekday', 'weekYear', 'isoWeekYear', 'isoWeek' ARE in the aliases table, so they normalize successfully but are NOT valid for durations and still hit this throw.

Source

Thrown at src/lib/duration/as.js:43

    } else {
        // handle milliseconds separately because of floating point math errors (issue #1867)
        days = this._days + Math.round(monthsToDays(this._months));
        switch (units) {
            case 'week':
                return days / 7 + milliseconds / 6048e5;
            case 'day':
                return days + milliseconds / 864e5;
            case 'hour':
                return days * 24 + milliseconds / 36e5;
            case 'minute':
                return days * 1440 + milliseconds / 6e4;
            case 'second':
                return days * 86400 + milliseconds / 1000;
            // Math.floor prevents floating point math errors here
            case 'millisecond':
                return Math.floor(days * 864e5) + milliseconds;
            default:
                throw new Error('Unknown unit ' + units);
        }
    }
}

function makeAs(alias) {
    return function () {
        return this.as(alias);
    };
}

var asMilliseconds = makeAs('ms'),
    asSeconds = makeAs('s'),
    asMinutes = makeAs('m'),
    asHours = makeAs('h'),
    asDays = makeAs('d'),
    asWeeks = makeAs('w'),
    asMonths = makeAs('M'),
    asQuarters = makeAs('Q'),

View on GitHub (pinned to 019806b26f)

Solutions

  1. Pass a valid duration unit alias: one of ms/s/m/h/d/w/M/Q/y (or the full names milliseconds/seconds/minutes/hours/days/weeks/months/quarters/years).
  2. If the unit comes from a variable, verify it is a defined string and one of the duration units before calling .as() (see validationCode / typeGuard).
  3. If you actually need a calendar field (day-of-month, weekday, day-of-year, iso-week, week-year), use a moment object (e.g. moment().date(), moment().isoWeekday()) not a duration - durations only measure elapsed time in time/month units.
  4. Default the unit with a known-good fallback when it is missing or unrecognized, instead of letting undefined reach .as().

Example fix

// before
const dur = moment.duration(90, 'minutes');
dur.as('minut'); // throws: Unknown unit undefined
dur.as('D');     // throws: Unknown unit date (calendar unit, not a duration unit)
dur.as();       // throws: Unknown unit undefined

// after
const dur = moment.duration(90, 'minutes');
dur.as('minutes'); // 90
dur.as('m');       // 90 (alias)
// day-of-month is a calendar field - use a moment, not a duration:
moment().date();
Defensive patterns

Strategy: validation

Validate before calling

// Mirror of the duration units as() actually accepts in src/lib/duration/as.js.
const DURATION_UNITS = new Set([
    'ms', 'milliseconds', 'millisecond',
    's', 'seconds', 'second',
    'm', 'minutes', 'minute',
    'h', 'hours', 'hour',
    'd', 'days', 'day',
    'w', 'weeks', 'week',
    'M', 'months', 'month',
    'Q', 'quarters', 'quarter',
    'y', 'years', 'year',
]);

// normalizeUnits lowercases as a fallback (src/lib/units/aliases.js:56), so check both.
function isValidDurationUnit(u) {
    if (typeof u !== 'string') return false;
    return DURATION_UNITS.has(u) || DURATION_UNITS.has(u.toLowerCase());
}

// usage - call BEFORE duration.as():
const unit = maybeUnitFromConfig;
const value = (unit != null && isValidDurationUnit(unit))
    ? dur.as(unit)
    : NaN; // or throw a clearer error with the offending value

Type guard

// TypeScript
type DurationUnit =
    | 'ms' | 'milliseconds' | 'millisecond'
    | 's' | 'seconds' | 'second'
    | 'm' | 'minutes' | 'minute'
    | 'h' | 'hours' | 'hour'
    | 'd' | 'days' | 'day'
    | 'w' | 'weeks' | 'week'
    | 'M' | 'months' | 'month'
    | 'Q' | 'quarters' | 'quarter'
    | 'y' | 'years' | 'year';

const DURATION_UNITS: ReadonlySet<string> = new Set([
    'ms', 'milliseconds', 'millisecond', 's', 'seconds', 'second',
    'm', 'minutes', 'minute', 'h', 'hours', 'hour', 'd', 'days', 'day',
    'w', 'weeks', 'week', 'M', 'months', 'month', 'Q', 'quarters',
    'quarter', 'y', 'years', 'year',
]);

function isDurationUnit(u: unknown): u is DurationUnit {
    return typeof u === 'string'
        && (DURATION_UNITS.has(u) || DURATION_UNITS.has(u.toLowerCase()));
}

// narrows `unit` so dur.as(unit) is statically safe:
if (isDurationUnit(unit)) {
    return dur.as(unit);
}

Try / catch

// Only if you genuinely can't validate up front. Narrow on the message so you don't swallow unrelated errors.
let value;
try {
    value = dur.as(unit);
} catch (e) {
    if (e instanceof Error && /^Unknown unit/.test(e.message)) {
        value = NaN; // or log + default
    } else {
        throw e;
    }
}

Prevention

When it happens

Trigger: Calling duration.as() with (a) a typo'd unit string e.g. dur.as('minut') -> normalizeUnits returns undefined -> throws 'Unknown unit undefined'; (b) no argument or a non-string e.g. dur.as() or dur.as(5) -> undefined -> throws 'Unknown unit undefined'; (c) a calendar-only unit e.g. dur.as('date') or dur.as('D') -> normalizes to 'date' -> throws 'Unknown unit date'; (d) an unsupported concept like dur.as('decade'). The alias getters (asMinutes, asSeconds, ...) call makeAs with a fixed valid alias so they never hit this path.

Common situations: Copying a unit string from a moment() date getter (e.g. .get('D') works for moments but 'D' -> 'date' throws for durations); reading the unit from a config/translation object whose key is missing (so the variable is undefined); passing a number or null by mistake; i18n maps where a translation key for the unit was never added; refactors that pass through user input without validating it.

Related errors


AI-assisted analysis of moment/moment@019806b26f (2026-08-04). Data as JSON: /data/errors/bb87b2b97d2e2ffe.json. Report an issue: GitHub.