actualbudget/actual · error

Unitialised context method called: onBudgetAction

Error message

Unitialised context method called: onBudgetAction

What it means

EnvelopeBudgetContext's default createContext value contains a stub onBudgetAction that throws, mirroring the ServerContext pattern: consumers must be rendered under the EnvelopeBudgetContext.Provider which supplies the real dispatch-to-budget handler. Hitting the stub means no provider is present above the caller.

Source

Thrown at packages/desktop-client/src/components/budget/envelope/EnvelopeBudgetContext.tsx:16

import React, { createContext, useContext } from 'react';
import type { ReactNode } from 'react';

import * as monthUtils from '@actual-app/core/shared/months';

type EnvelopeBudgetContextDefinition = {
  summaryCollapsed: boolean;
  onBudgetAction: (month: string, action: string, arg?: unknown) => void;
  onToggleSummaryCollapse: () => void;
  currentMonth: string;
};

const EnvelopeBudgetContext = createContext<EnvelopeBudgetContextDefinition>({
  summaryCollapsed: false,
  onBudgetAction: () => {
    throw new Error('Unitialised context method called: onBudgetAction');
  },
  onToggleSummaryCollapse: () => {
    throw new Error(
      'Unitialised context method called: onToggleSummaryCollapse',
    );
  },
  currentMonth: 'unknown',
});

type EnvelopeBudgetProviderProps = Omit<
  EnvelopeBudgetContextDefinition,
  'currentMonth'
> & {
  children: ReactNode;
};
export function EnvelopeBudgetProvider({
  summaryCollapsed,
  onBudgetAction,

View on GitHub (pinned to d4334cb6e6)

Solutions

  1. Wrap the consumer in the EnvelopeBudgetContext.Provider (as the envelope budget page does) supplying onBudgetAction and the other fields.
  2. In tests/stories, provide a mock context value: onBudgetAction: vi.fn(), onToggleSummaryCollapse: vi.fn(), currentMonth: '2026-01'.
  3. Assert provider presence early by consuming currentMonth in dev — the sentinel 'unknown' value indicates the stub context is active.

Example fix

// before (test)
render(<EnvelopeBudgetCell month="2026-01" />);

// after
render(
  <EnvelopeBudgetContext.Provider value={{ summaryCollapsed: false, onBudgetAction: vi.fn(), onToggleSummaryCollapse: vi.fn(), currentMonth: '2026-01' }}>
    <EnvelopeBudgetCell month="2026-01" />
  </EnvelopeBudgetContext.Provider>
);
Defensive patterns

Strategy: try-catch

Validate before calling

const ctx = useContext(EnvelopeBudgetContext);
const isProviderReady = ctx.currentMonth !== 'unknown' && typeof ctx.onBudgetAction === 'function';
if (!isProviderReady) throw new Error('EnvelopeBudgetContext.Provider missing');

Type guard

function hasEnvelopeBudgetContext(ctx: EnvelopeBudgetContextDefinition): boolean {
  return ctx.currentMonth !== 'unknown' && typeof ctx.onBudgetAction === 'function';
}

Try / catch

try {
  onBudgetAction(month, { type: 'budget-amount' });
} catch (e) {
  if (String(e.message).includes('Unitialised context method')) {
    // provider absent: skip or route back to budget page
  } else throw e;
}

Prevention

When it happens

Trigger: Invoking onBudgetAction(month, action) from a component (or test/story render) that is not inside <EnvelopeBudgetContext.Provider>, e.g. envelope budget widgets rendered standalone.

Common situations: Unit tests of EnvelopeBudgetCell/BalanceCell without the provider wrapper; rendering budget subcomponents in isolation; moving a component above the provider during a refactor.

Related errors


AI-assisted analysis of actualbudget/actual@d4334cb6e6 (2026-08-29). Data as JSON: /api/errors/4a93123540a4e4cb. Report an issue: GitHub.