hcengineering/platform · warning
Unable to calculate negative position ${pos}
Error message
Unable to calculate negative position ${pos} What it means
getNegativePosition computes the Nth occurrence of a weekday within a month for BYDAY/BYSETPOS handling. If it iterates through the whole period without collecting Math.abs(pos) occurrences, the requested negative position does not exist in that month and the error is thrown.
Source
Thrown at plugins/calendar/src/utils.ts:139
}
}
return false
}
function getNegativePosition (date: Date, weekday: string, pos: number): number | undefined {
const lastDayOfMonth = new Date(date.getFullYear(), date.getMonth() + 1, 0).getDate()
const occurrences = []
for (let day = lastDayOfMonth; day >= 1; day--) {
const tempDate = new Date(date.getFullYear(), date.getMonth(), day)
if (getWeekday(tempDate) === weekday) {
occurrences.push(day)
}
if (occurrences.length === Math.abs(pos)) {
return occurrences.pop()
}
}
throw new Error(`Unable to calculate negative position ${pos}`)
}
function generateMonthlyValues (rule: RecurringRule, currentDate: Date, from: Timestamp, to: Timestamp): Timestamp[] {
const values: Timestamp[] = []
const { count, endDate, interval } = rule
let { byDay, byMonthDay, bySetPos } = rule
let i = 0
if (byDay == null && byMonthDay == null) {
byMonthDay = [currentDate.getDate()]
}
while (true) {
const next = new Date(currentDate).setMonth(currentDate.getMonth() + (interval ?? 1), 1)
const end = new Date(new Date(currentDate).setMonth(currentDate.getMonth() + 1, 1))
let date = currentDate
const candidates: Date[] = []
View on GitHub (pinned to 63e28dc964)
Solutions
- Clamp/validate negative positions in rules to values that exist for every affected month (e.g. -1 to -4 for weekly positions)
- Catch the error in expansion code and skip non-existent occurrences for that month
- Normalize imported iCalendar BYSETPOS values against month feasibility at import
Example fix
// before: rule with bySetPos: -5 for MONTHLY on Monday, February throws // after: clamp before expansion const maxPos = Math.floor(31 / 7) // 4 weekly occurrences guaranteed const pos = Math.max(rule.bySetPos, -maxPos)
Defensive patterns
Strategy: try-catch
Validate before calling
const possible = Math.floor(daysInMonth(currentDate) / 7)
if (Math.abs(rule.bySetPos ?? -1) > possible) {
// position does not exist in this month — skip occurrence
} Try / catch
try {
day = getNegativePosition(rule, currentDate, pos)
} catch (err) {
if ((err as Error).message.startsWith('Unable to calculate negative position')) {
continue // occurrence does not exist in this month
} else throw err
} Prevention
- Constrain negative BYSETPOS values to -1..-4 when authoring rules
- Validate imported iCalendar BYSETPOS against month feasibility
- Test recurrence expansion on short months like February
When it happens
Trigger: A recurring rule requests e.g. the 5th-last Monday (pos=-5) of a month that has fewer than 5 Mondays, or byDay/byMonthDay data is inconsistent with the month being expanded.
Common situations: Recurrence rules imported from external calendars using large negative set positions; hand-crafted rules like 'last fifth weekday'; month-length edge cases (February) during event expansion.
Related errors
- Invalid recurring rule frequency
- Calendar service URL or token is not defined
- Email is not defined in integration
- 'event' or 'workspace' or 'type' is missing
- Missing env variables: ${missingEnv.join(', ')}
AI-assisted analysis of hcengineering/platform@63e28dc964 (2026-08-29).
Data as JSON: /api/errors/41bdbdb044a48871.
Report an issue: GitHub.