actualbudget/actual · error

Unitialised context method called: onBudgetAction

Error message

Unitialised context method called: onBudgetAction

What it means

TrackingBudgetContext is created with placeholder defaults: onBudgetAction is a stub function that throws when called. The error means a component called the context's onBudgetAction without a TrackingBudgetContext.Provider being mounted above it (or the provider received no real implementation), so the consumer fell back to the createContext defaults.

Solutions

  1. Wrap the consuming component tree in TrackingBudgetContext.Provider passing a real onBudgetAction implementation.
  2. Ensure the component is rendered inside the tracking-budget layout where the provider lives (packages/desktop-client/src/components/budget/tracking/TrackingBudgetContext.tsx).
  3. In tests, wrap the component under test with the provider (or a mock with jest.fn()/vi.fn() as onBudgetAction).
  4. In the hook, add a dev-time guard that reports the context was consumed without its provider.

Example fix

// before
export function MyWidget() {
  const { onBudgetAction } = useTrackingBudget(); // throws when called

// after
export function MyWidget() {
  return (
    <TrackingBudgetContext.Provider value={{ summaryCollapsed: false, onBudgetAction: handleBudgetAction, onToggleSummaryCollapse: toggle, currentMonth: month }}>
      <WidgetInner />
    </TrackingBudgetContext.Provider>
  );
Defensive patterns

Strategy: try-catch

Validate before calling

// guard before calling:
const ctx = useContext(TrackingBudgetContext);
const isProviderMissing = ctx.onBudgetAction === TrackingBudgetContext._currentValue?.onBudgetAction; // or expose a hasProvider flag on the context value
if (!ctx || typeof ctx.onBudgetAction !== 'function') throw new Error('TrackingBudgetContext provider missing');

Type guard

function hasTrackingBudgetContext(ctx: TrackingBudgetContextDefinition | null): ctx is TrackingBudgetContextDefinition {
  return ctx != null && typeof ctx.onBudgetAction === 'function' && typeof ctx.onToggleSummaryCollapse === 'function';
}

Try / catch

try {
  onBudgetAction('budget-set-amount', payload);
} catch (err) {
  if (err instanceof Error && err.message.includes('Unitialised context method called')) {
    logger.warn('TrackingBudgetContext not provided; budget action skipped');
  } else {
    throw err;
  }
}

Prevention

When it happens

Trigger: Calling onBudgetAction(...) from useTrackingBudget (or useContext(TrackingBudgetContext)) in a component rendered outside of the TrackingBudgetContext.Provider that supplies the real handler, e.g. a budget widget rendered under the non-tracking (report/basic) budget layout.

Common situations: Moving a component that uses tracking-budget hooks into the envelope/budget-rollover layout which uses a different context; testing a component in isolation without wrapping it in the provider; a refactor that renamed or removed the Provider while consumers stayed.

Related errors


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

Appendix: source

Thrown at packages/desktop-client/src/components/budget/tracking/TrackingBudgetContext.tsx:16

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

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

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

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

type TrackingBudgetProviderProps = Omit<
  TrackingBudgetContextDefinition,
  'currentMonth'
> & {
  children: ReactNode;
};
export function TrackingBudgetProvider({
  summaryCollapsed,
  onBudgetAction,

View on GitHub (pinned to d4334cb6e6)