we-promise/sure · error · Provider::Openai::Error
No categories available for auto-categorization
Error message
No categories available for auto-categorization
What it means
Raised by Provider::Openai#auto_categorize when the user_categories array is blank. The LLM prompt needs the family's category list to classify transactions against; with zero categories there is nothing to map to, so the call is rejected before any API request or Langfuse trace is made. The family id (or 'unknown') is logged at error level first, so the log line identifies whose configuration is broken.
Source
Thrown at app/models/provider/openai.rb:111
# Budget available for a one-shot (non-chat) request's full input,
# excluding reserved response tokens AND the system/instructions prompt.
# Drives the batch slicer for the auto_categorize / auto_detect_merchants /
# enhance_provider_merchants calls — each ships ~200–400 tokens of
# instructions + JSON schema that aren't counted in `fixed_tokens`.
def max_input_tokens
[ context_window - max_response_tokens - system_prompt_reserve, 256 ].max
end
def max_items_per_call
positive_budget(ENV["LLM_MAX_ITEMS_PER_CALL"], Setting.llm_max_items_per_call, 25)
end
def auto_categorize(transactions: [], user_categories: [], model: "", family: nil, json_mode: nil)
with_provider_response do
if user_categories.blank?
family_id = family&.id || "unknown"
Rails.logger.error("Cannot auto-categorize transactions for family #{family_id}: no categories available")
raise Error, "No categories available for auto-categorization"
end
effective_model = model.presence || @default_model
trace = create_langfuse_trace(
name: "openai.auto_categorize",
input: { transactions: transactions, user_categories: user_categories }
)
batches = slice_for_context(transactions, fixed: user_categories)
result = batches.flat_map do |batch|
AutoCategorizer.new(
client,
model: effective_model,
transactions: batch,
user_categories: user_categories,
custom_provider: custom_provider?,View on GitHub (pinned to e69894adb9)
Solutions
- Ensure the family has at least one category before offering/running auto-categorization (seed default categories at family creation).
- Guard at the call site: skip the job unless family.categories.active.exists?.
- If categories were deleted mid-flight, re-trigger after the user restores or recreates categories.
- In tests, pass user_categories: [ { name: "Groceries" } ] (or create fixture categories) so the blank check passes.
Example fix
# before AutoCategorizeJob.perform_later(family.id) # after return if family.categories.active.empty? AutoCategorizeJob.perform_later(family.id)
Defensive patterns
Strategy: validation
Validate before calling
return if family.categories.active.none? # or seed defaults at family creation SeedCategories.call(family) if family.categories.active.none?
Try / catch
begin
provider.auto_categorize(transactions: txns, user_categories: cats, family: family)
rescue Provider::Openai::Error => e
return { skipped: true } if e.message.include?("No categories available")
raise
end Prevention
- Provision default categories at family creation so the precondition always holds.
- Guard jobs with family.categories.active.exists? before enqueuing categorization work.
- Pass user_categories explicitly at every call site — never rely on the empty default.
When it happens
Trigger: Invoking auto-categorization for a brand-new family that never created categories; a family whose categories were all deleted or archived leaving none active; calling the method programmatically without forwarding the categories argument (family: nil plus empty defaults).
Common situations: Onboarding flows that trigger categorization before the default category set is provisioned;RSpec/VCR tests stubbing family but not categories; background jobs replaying old payloads after a user wiped their categories; a caller passing categories under a different keyword and silently hitting the [] default.
Related errors
- No categories available for auto-categorization
- No message content found in response
- {e.record.errors.full_messages.to_sentence.presence || e.mes
- OpenAI stream ended without a completion event. This usually
- No LLM provider for auto-categorization
AI-assisted analysis of we-promise/sure@e69894adb9 (2026-08-21).
Data as JSON: /api/errors/cc78447fd0197348.
Report an issue: GitHub.