we-promise/sure · warning · Assistant::Error
Invalid month: #{raw}. Use YYYY-MM or MMM-YYYY.
Error message
Invalid month: #{raw}. Use YYYY-MM or MMM-YYYY. What it means
Raised by Assistant::Function::MonthResolvable#parse_month when the month argument does not strictly match \A\d{4}-\d{2}\z (YYYY-MM) or \A[A-Za-z]{3}-\d{4}\z (MMM-YYYY). The anchor check exists because Date.strptime ignores trailing characters ("2026-08-15" would silently parse with %Y-%m), so any other shape is rejected up front. UpdateBudget rescues Assistant::Error and returns { success: false, error: "invalid_params", message: ... }.
Source
Thrown at app/models/assistant/function/month_resolvable.rb:23
private
def resolve_month_start(raw)
base = parse_month(raw)
return (base || Date.current).beginning_of_month unless family.uses_custom_month_start?
# Match Budget.param_to_date for explicit slugs so the input round-trips with the response.
base ? Date.new(base.year, base.month, family.month_start_day) : family.custom_month_start_for(Date.current)
end
def parse_month(raw)
return nil if raw.blank?
# Date.strptime ignores trailing characters, so guard with strict anchors first.
fmt = case raw
when /\A\d{4}-\d{2}\z/ then "%Y-%m"
when /\A[A-Za-z]{3}-\d{4}\z/ then "%b-%Y"
end
raise Assistant::Error, "Invalid month: #{raw}. Use YYYY-MM or MMM-YYYY." if fmt.nil?
Date.strptime(raw, fmt)
rescue ArgumentError
raise Assistant::Error, "Invalid month: #{raw}. Use YYYY-MM or MMM-YYYY."
end
end
View on GitHub (pinned to e69894adb9)
Solutions
- Pass the month in one of the two accepted shapes: "2026-08" or "Aug-2026" (three-letter abbreviation, hyphen, four-digit year).
- If the value comes from a Date object, normalize it first with date.strftime("%Y-%m") before calling the function.
- If you control the caller, pre-validate with the same anchored regexes and reformat instead of retrying blindly.
Example fix
# before
update_budget.call({ "month" => "August 2026", "budgeted_spending" => 6500 })
# after — normalize to the accepted slug first
month = Date.parse("August 2026").strftime("%Y-%m")
update_budget.call({ "month" => month, "budgeted_spending" => 6500 }) Defensive patterns
Strategy: validation
Validate before calling
MONTH_SLUG = /\A(?:\d{4}-\d{2}|[A-Za-z]{3}-\d{4})\z/
raise ArgumentError, "month must be YYYY-MM or MMM-YYYY" unless month.to_s.match?(MONTH_SLUG) Type guard
# Ruby
def valid_month_slug?(raw)
raw.is_a?(String) && raw.match?("\\A(?:\\d{4}-\\d{2}|[A-Za-z]{3}-\\d{4})\\z")
end Try / catch
begin
update_budget.call(params)
rescue Assistant::Error => e
# call() already converts this to { success: false, error: "invalid_params" } — check the result instead
end Prevention
- Always derive month slugs from Date#strftime("%Y-%m") instead of hand-formatting strings.
- When passing user-typed months, normalize via Date.parse(...).strftime('%Y-%m') inside a rescue before calling the tool.
- Feed the LLM the exact accepted formats in the prompt and echo them back from get_budget so round-trips stay canonical.
When it happens
Trigger: Calling update_budget with month: "2026/08" (slash), "Aug 2026" (space instead of hyphen), "2026-8" (single-digit month), "202608", "last month", or "August 2026" — none match either anchored regex, so fmt is nil and the raise at app/models/assistant/function/month_resolvable.rb:23 fires.
Common situations: LLM free-forming a natural-language month instead of the documented format; user-typed values passed through unnormalized; months imported from other tools that use MM/DD or 'August 2026' styles.
Related errors
- #{label} must be a non-negative number.
- Each categories entry needs a category name or id.
- '#{ref}' is the unallocated remainder of budgeted_spending a
- #{key} must be an ISO 8601 date
- #{key} must be an ISO 8601 date
AI-assisted analysis of we-promise/sure@e69894adb9 (2026-08-21).
Data as JSON: /api/errors/9634a46ea8fb5fc7.
Report an issue: GitHub.