- Dharmagya
- panchang docs
- Errors & Compatibility
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
}
}package main
import (
"errors"
"fmt"
"time"
"github.com/ishankgupta95/panchang/source/go/v5/panchang"
"github.com/ishankgupta95/panchang/source/go/v5/types"
)
func main() {
s := panchang.New()
_, _, err := s.GetDailyPanchang(
time.Date(2026, 1, 15, 0, 0, 0, 0, time.UTC),
types.GeoLocation{Latitude: 95, Longitude: 73.86},
types.PanchangOptions{Timezone: panchang.OffsetMinutes(330)})
var pe *types.PanchangError
if errors.As(err, &pe) {
fmt.Println(pe.Code) // INVALID_LATITUDE
fmt.Println(pe.Error()) // 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.
| Code | Thrown when |
|---|---|
INVALID_DATE | the 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_LATITUDE | latitude outside [-90, 90] |
INVALID_LONGITUDE | longitude outside [-180, 180] |
INVALID_ELEVATION | elevation is not a finite number, or is below -500 metres |
INVALID_TIMEZONE | the 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_AYANAMSA | unknown ayanamsa slug |
INVALID_INPUT | an 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_FAILED | a 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_SUNRISE | getSunrise found no event: polar day or night |
NO_SUNSET | getSunset found no event |
SEARCH_DIVERGED | a root search failed to converge. Please report these |
CIRCUMPOLAR | a 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_DIVERGED | a 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_ERROR | a 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.
| Input | Up to 5.3 | Since 5.4 |
|---|---|---|
getSunrise(new Date('x'), loc) | never returned | INVALID_DATE |
getSunrise(new Date(4.6e15), loc), past 2^52 ms from 1970 | never returned | INVALID_DATE |
getAyanamsa(new Date('x')) | NaN | INVALID_DATE |
computeFestivalsForYear(25, …) | the 1925 list | INVALID_DATE |
convertHinduToGregorian with vikramSamvat: 2082.5 | [] | INVALID_DATE |
computeBhava with houseSystem: 'koch' | TypeError | INVALID_INPUT |
computeDivisionalChart(…, 'D60') | TypeError | INVALID_INPUT |
computeDignity('Pluto', 0) | TypeError | INVALID_INPUT |
computeYogas with an unknown types entry | silently [] | INVALID_INPUT |
computeRahuKalam(sunrise, sunset, 7) | an Invalid Date window | INVALID_INPUT |
computeVimshottariDasha with a NaN Moon longitude | Invalid Date periods | INVALID_INPUT |
computeVimshottariPratyantar with an unknown lord | a plain Error | INVALID_INPUT |
formatInZone(date, 5.5) | "…+00:undefined" | INVALID_TIMEZONE |
buildMoonPhasesTable with languages: ['fr'] | TypeError | RangeError (Go: INVALID_INPUT) |
computeKpCuspalSubLords at 66.5° N, 18° E, 20 March 2025 08:00 UTC | PLACIDUS_DIVERGED | all 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// inside main, with s := panchang.New()
_, err := s.ComputeSunrise(
time.Date(2026, 6, 21, 0, 0, 0, 0, time.UTC),
types.GeoLocation{Latitude: 78.22, Longitude: 15.65}, 2)
// One code: IsCode, since a code is a value and not an error.
if panchang.IsCode(err, types.ErrNoSunrise) {
fmt.Println("polar day or night")
}
// The four codes with a sentinel also work as an errors.Is target.
fmt.Println(errors.Is(err, types.ErrNoSunriseSentinel)) // true
// Several codes: pull the error out and switch.
var pe *types.PanchangError
if errors.As(err, &pe) {
switch pe.Code {
case types.ErrNoSunrise:
fmt.Println("switch:", "polar day or night")
case types.ErrInvalidLatitude:
fmt.Println("switch:", "bad latitude")
default:
fmt.Println("switch:", pe.Code, pe)
}
}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// inside main
codes := panchang.AllErrorCodes()
fmt.Println(len(codes)) // 14
for _, c := range codes {
fmt.Println(c)
}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
}// inside main, with s := panchang.New()
svalbard := types.GeoLocation{Latitude: 78.22, Longitude: 15.65}
midsummer := time.Date(2026, 6, 21, 0, 0, 0, 0, time.UTC)
// The day itself: ok is false and err is nil. This is TypeScript's null.
_, ok, err := s.GetDailyPanchang(midsummer, svalbard,
types.PanchangOptions{Timezone: panchang.OffsetMinutes(120)})
fmt.Println(ok, err) // false <nil>
// The rise/set primitive: an error carrying the reason.
// 2 is the search window in days; TypeScript defaults it, Go does not.
_, err = s.ComputeSunrise(midsummer, svalbard, 2)
fmt.Println(panchang.IsCode(err, types.ErrNoSunrise)) // trueThe 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.
| Environment | Support |
|---|---|
| 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.
