Skip to content
Documentation · all sections

Errors & Compatibility

panchang · v5.4.0 · MIT

The error codes both languages share, what happens at polar latitudes, and where the library runs — Node, browsers, React Native, Expo and Go.

PanchangError

Bad input throws a PanchangError. It carries a code you can branch on and a message you can log. Go returns a *types.PanchangError with the same Code values, so error handling ports across without a lookup table.

import { getDailyPanchang, PanchangError } from 'panchang-ts';

try {
  getDailyPanchang(
    new Date('2026-01-15T00:00:00Z'),
    { latitude: 95, longitude: 73.86 },
    { timezone: 330 },
  );
} catch (e) {
  if (e instanceof PanchangError) {
    console.log(e.code);     // INVALID_LATITUDE
    console.log(e.message);  // Latitude must be a finite number between -90 and 90, got 95
  }
}

A few TypeScript argument checks throw a plain RangeError instead: a rashi, nakshatra or tithi index out of range; a vara index outside 0 to 6 in classifyPanchaka, computeAnandadiYoga and computeVaraTithiYogas; a masa index, paksha or paksha tithi out of range in convertHinduToGregorian; a nakshatra pada outside 1 to 4; a year that is not a whole number; a range whose start is after its end; a count below 1; an empty language list; and, since 5.4, a table language other than en or hi. Go, which has no RangeError, reports them as INVALID_INPUT, so in TypeScript catch both.

There are fourteen codes. Each one is a member of the exported PanchangErrorCode union, so TypeScript checks a switch over them for exhaustiveness.

CodeThrown when
INVALID_DATEthe date is not a valid Date; or its year is outside [1900, 2100] in the daily and instant panchang, the charts, the dashas, Sade Sati, the converters, muhurta scoring, the listings and range searches, getUpcomingEclipses and the table builders (since 5.4 a year from 0 to 99 is refused there, not read as 1900 to 1999); or a rise or set search would pass 2^52 ms from 1970. A vikramSamvat that is not a whole number reports it too. The rise and set primitives, the sidereal Sun and Moon longitudes, getAyanamsa, computePlanetaryPositions, computeSamvat, the single-eclipse lookups (getUpcomingSolarEclipse, getUpcomingLunarEclipse, getEclipseDuringDay), computeEkadashiDatesForYear, computeSankrantisForYear and the solar-region getHinduNewYear take any year, as do the window helpers that take sunrise and sunset instants you already have
INVALID_LATITUDElatitude outside [-90, 90]
INVALID_LONGITUDElongitude outside [-180, 180]
INVALID_ELEVATIONelevation is not a finite number, or is below -500 metres
INVALID_TIMEZONEthe numeric UTC offset is not an integer between -720 and 840. formatInZone takes any whole-minute offset and reports a fraction the same way. Go also reports a missing timezone, where untyped JavaScript silently uses the host's zone
INVALID_AYANAMSAunknown ayanamsa slug
INVALID_INPUTan argument is bad in some other way: an unknown reference mode, house system, divisional, graha, dasha lord, yoga type or node-aspect mode; a vara index outside 0 to 6 in the Rahu Kalam, Gulika Kalam, Yamaganda and Gowri helpers; a Moon longitude that is NaN or infinite (a finite one outside [0, 360) is wrapped); a location passed to resolveLocation that is not an object; a year age below 1. Go’s versions of those four vara helpers have no error return and panic instead
TIMEZONE_RESOLUTION_FAILEDa zone name did not resolve: an unknown IANA name, '' or 'Local', or any name on a runtime without full Intl (older Hermes). Go reads "" as UTC and "Local" as the host's zone
NO_SUNRISEgetSunrise found no event: polar day or night
NO_SUNSETgetSunset found no event
SEARCH_DIVERGEDa root search failed to converge. Please report these
CIRCUMPOLARa Placidus-KP cusp is circumpolar at that moment. Like the next code, it happens only beyond the polar circles, above about ±66.56° latitude, where whole-sign and equal houses still work
PLACIDUS_DIVERGEDa Placidus-KP cusp search did not settle, again only beyond the polar circles. Up to 5.3 it also fired a little inside them, from about 66.3°
SAHAM_DEPENDENCY_ERRORa Varshaphala saham formula needed Punya before Punya had been worked out

What 5.4 changed

5.4 adds no error code and removes none. Calls that used to hang, crash with a raw TypeError or return garbage now throw, and one house chart that used to fail now computes. Every row was run on both builds.

InputUp to 5.3Since 5.4
getSunrise(new Date('x'), loc)never returnedINVALID_DATE
getSunrise(new Date(4.6e15), loc), past 2^52 ms from 1970never returnedINVALID_DATE
getAyanamsa(new Date('x'))NaNINVALID_DATE
computeFestivalsForYear(25, …)the 1925 listINVALID_DATE
convertHinduToGregorian with vikramSamvat: 2082.5[]INVALID_DATE
computeBhava with houseSystem: 'koch'TypeErrorINVALID_INPUT
computeDivisionalChart(…, 'D60')TypeErrorINVALID_INPUT
computeDignity('Pluto', 0)TypeErrorINVALID_INPUT
computeYogas with an unknown types entrysilently []INVALID_INPUT
computeRahuKalam(sunrise, sunset, 7)an Invalid Date windowINVALID_INPUT
computeVimshottariDasha with a NaN Moon longitudeInvalid Date periodsINVALID_INPUT
computeVimshottariPratyantar with an unknown lorda plain ErrorINVALID_INPUT
formatInZone(date, 5.5)"…+00:undefined"INVALID_TIMEZONE
buildMoonPhasesTable with languages: ['fr']TypeErrorRangeError (Go: INVALID_INPUT)
computeKpCuspalSubLords at 66.5° N, 18° E, 20 March 2025 08:00 UTCPLACIDUS_DIVERGEDall twelve cusps

See Upgrading 5.3 → 5.4 for the values that move.

Branching on a code

In TypeScript, check the instance and then switch on code. In Go, use panchang.IsCode when you only care about one code, and errors.As when you want to switch over several. A code is a value rather than an error, so errors.Is cannot take one. It takes one of the four sentinels instead: types.ErrNoSunriseSentinel and its siblings.

import { getSunrise, PanchangError } from 'panchang-ts';

try {
  getSunrise(new Date('2026-06-21T00:00:00Z'), { latitude: 78.22, longitude: 15.65 });
} catch (e) {
  if (!(e instanceof PanchangError)) throw e;
  switch (e.code) {
    case 'NO_SUNRISE':
      console.log('polar day or night');
      break;
    case 'INVALID_LATITUDE':
      console.log('bad latitude');
      break;
    default:
      console.log(e.code, e.message);
  }
}
// polar day or night

Listing every code

PanchangErrorCode is a type, so it is gone at runtime. Write the list out yourself if you need one. Go ships the list as a function.

import type { PanchangErrorCode } from 'panchang-ts';

const ALL_CODES: PanchangErrorCode[] = [
  'INVALID_LATITUDE', 'INVALID_LONGITUDE', 'INVALID_ELEVATION', 'INVALID_DATE',
  'INVALID_TIMEZONE', 'INVALID_AYANAMSA', 'INVALID_INPUT', 'TIMEZONE_RESOLUTION_FAILED',
  'NO_SUNRISE', 'NO_SUNSET', 'SEARCH_DIVERGED', 'CIRCUMPOLAR',
  'PLACIDUS_DIVERGED', 'SAHAM_DEPENDENCY_ERROR',
];
console.log(ALL_CODES.length);  // 14

Polar locations

Far enough north or south the Sun does not rise at all, and the Hindu day has no start. getDailyPanchang and getInstantPanchang return null for those days rather than throwing. In Go the second return value is false and the error is nil. They also return null on the last day before polar day or polar night, which has a sunrise but no sunset, or no next sunrise, within two days after it (Longyearbyen in Europe/Oslo, 18 April and 26 October 2025).

Since 5.4, getDailyPanchang returns null for every civil day that holds no sunrise. Up to 5.3 some of those days came back as the next day's panchang instead, so one Hindu day appeared on two dates. Two examples: the last sunless day before the first sunrise after polar night (Longyearbyen, 14 February 2025, in Europe/Oslo), and a day that a fixed offset far from the location's solar time leaves without one (Kolkata with timezone: 0, 6 October 2025, whose sunrise falls just after midnight on the 7th).

import { getDailyPanchang, getSunrise, PanchangError } from 'panchang-ts';

const svalbard = { latitude: 78.22, longitude: 15.65 };
const midsummer = new Date('2026-06-21T00:00:00Z');

// The day itself: null, not a throw.
console.log(getDailyPanchang(midsummer, svalbard, { timezone: 120 }));  // null

// The rise/set primitive: a throw carrying the reason.
try {
  getSunrise(midsummer, svalbard);
} catch (e) {
  console.log(e instanceof PanchangError, (e as PanchangError).code);  // true NO_SUNRISE
}

The low-level primitives are stricter, because a direct caller wants the reason. getSunrise and getSunset throw NO_SUNRISE and NO_SUNSET. getMoonrise and getMoonset return null instead, since the Moon skips days everywhere on Earth and that is not an error. Go's ComputeSunrise takes the search window in days as a third argument; TypeScript defaults it to 2, Go has no default.

Compatibility

The rows below are JavaScript runtimes. Go is supported as well, through the github.com/ishankgupta95/panchang/source/go/v5 module, and raises the same error codes.

EnvironmentSupport
Node.js ≥ 22 (per the package "engines" field)Supported
React Native (Hermes)Supported — pass timezone as a number
Expo (managed + bare)Supported
Browser (modern, ESM)Supported
Browser (legacy / IE)Not supported

The JavaScript build targets ES2020 and ships both ESM and CJS with full .d.ts files. It has no runtime dependencies. It is marked sideEffects: false, so bundlers tree-shake it. The four subpath entries (panchang-ts/festivals, /eclipses, /moon-phases, /muhurta) import no astronomy code — see Types & Exports.