actualbudget/actual · error
Unknown format type: ${type}
Error message
Unknown format type: ${type} What it means
format() switches only over the documented FormatType union ('string', 'number', 'percentage', 'financial', 'financial-with-sign', 'financial-no-decimals'). Any other type value reaches the default branch and throws 'Unknown format type: <type>'. It protects against typos and stale string literals passed as the format type.
Source
Thrown at packages/desktop-client/src/hooks/useFormat.ts:106
}
if (typeof localValue !== 'number') {
throw new Error(
'Value is not a number (' + typeof localValue + '): ' + localValue,
);
}
return {
numericValue: localValue,
formattedString: integerToCurrency(
localValue,
formatter,
decimalPlaces,
),
};
}
default:
throw new Error('Unknown format type: ' + type);
}
}
export function useFormat(): UseFormatResult {
const [numberFormatPref] = useSyncedPref('numberFormat');
const [hideFractionPref] = useSyncedPref('hideFraction');
const [defaultCurrencyCodePref] = useSyncedPref('defaultCurrencyCode');
const [symbolPositionPref] = useSyncedPref('currencySymbolPosition');
const [spaceEnabledPref] = useSyncedPref(
'currencySpaceBetweenAmountAndSymbol',
);
const activeCurrency = useMemo(() => {
return getCurrency(defaultCurrencyCodePref || '');
}, [defaultCurrencyCodePref]);
const numberFormatConfig = useMemo(
() =>View on GitHub (pinned to d4334cb6e6)
Solutions
- Use only the FormatType union values: string, number, percentage, financial, financial-with-sign, financial-no-decimals
- Import and use the FormatType type so TypeScript rejects invalid literals at compile time (avoid typing the arg as string/any)
- If you need a new type, extend the FormatType union and the switch in useFormat.ts rather than passing a custom string
- Map legacy type names to current ones at the boundary before calling
Example fix
// before
format(value, 'currency'); // not a FormatType
// after
import type { FormatType } from './useFormat';
const type: FormatType = 'financial';
format(value, type); Defensive patterns
Strategy: type-guard
Validate before calling
const FORMAT_TYPES = ['string','number','percentage','financial','financial-with-sign','financial-no-decimals'] as const;
if (!FORMAT_TYPES.includes(type as FormatType)) throw new Error(`Unknown format type: ${type}`); Type guard
function isFormatType(v: unknown): v is FormatType {
return typeof v === 'string' && ['string','number','percentage','financial','financial-with-sign','financial-no-decimals'].includes(v);
} Try / catch
let out: string;
try {
out = format(value, type);
} catch (e) {
if (e instanceof Error && e.message.startsWith('Unknown format type')) {
console.warn(`Unknown format type ${type}, defaulting to string`);
out = format(value, 'string');
} else throw e;
} Prevention
- Always annotate the type argument as FormatType so invalid literals fail at compile time
- Whitelist format types read from user config with isFormatType before use
- Map legacy/foreign format names to FormatType at integration boundaries
- When adding a format type, update the union, the switch, and this guard together
When it happens
Trigger: Calling format(v, 'currency') or format(v, 'int') — names from other libraries or older Actual versions; a typo like 'financail'; a string from config/props typed as any where a FormatType is expected.
Common situations: Copy-pasting formatter calls from other codebases; migrating from an older API that used different type names; reading the format type from user-editable config without whitelisting.
Related errors
- Unknown display type: ${String(displayType)}
- Unknown template type: ${String(type satisfies undefined)}
- Unknown display type: ${String(visualType satisfies never)}
- Unknown display type: ${String(type satisfies never)}
- Unhandled action type: ${action.type}
AI-assisted analysis of actualbudget/actual@d4334cb6e6 (2026-08-29).
Data as JSON: /api/errors/4f12e67f0ec93814.
Report an issue: GitHub.