we-promise/sure · error · Provenance::Citation::InvalidError
source citation is required
Error message
source citation is required
What it means
Provenance::Citation.parse! raises Provenance::Citation::InvalidError 'source citation is required' when the input, after to_s.strip, is blank (nil, empty string, whitespace). A citation is mandatory provenance metadata: every agent-recorded value must name where it came from, so absence is rejected at the write boundary.
Source
Thrown at app/models/provenance/citation.rb:43
# match here, folding the grade into the citation text and yielding an
# ungraded source — silently losing the reliability the caller supplied.
FORMAT = /\A(?<estimated>estimated:\s)?(?<text>.+?)(?:\s?\(grade:\s*(?<grade>[ABC])\))?\z/
# Matched separately so "(grade: D)" fails loudly instead of folding into the
# citation text and passing as an ungraded — but plausible-looking — source.
GRADE_SUFFIX = /\(grade:\s*(?<grade>[^)]*)\)\s*\z/
ESTIMATED_MARKER = /\Aestimated\s*:/i
class InvalidError < StandardError; end
attr_reader :raw, :text, :grade
class << self
# Returns a Citation, or raises InvalidError with a message written for the
# caller that has to fix it (an agent, usually).
def parse!(raw)
value = raw.to_s.strip
raise InvalidError, "source citation is required" if value.blank?
raise InvalidError, "source citation must be #{MAX_LENGTH} characters or fewer" if value.length > MAX_LENGTH
if value.match?(ESTIMATED_MARKER) && !value.start_with?(ESTIMATED_PREFIX)
raise InvalidError, "estimated values must start with the exact prefix #{ESTIMATED_PREFIX.inspect}"
end
if (suffix = value.match(GRADE_SUFFIX)) && !GRADES.include?(suffix[:grade])
raise InvalidError, "reliability grade must be one of #{GRADES.join(", ")} (got #{suffix[:grade].inspect})"
end
match = value.match(FORMAT)
raise InvalidError, "source citation does not match #{grammar}" unless match
text = match[:text].to_s.strip
if text.length < MIN_TEXT_LENGTH
raise InvalidError, "source citation must name the document it came from"
end
View on GitHub (pinned to e69894adb9)
Solutions
- Supply a citation naming the document, e.g. 'Private bank statement 2026-03-31, line 12'.
- If the value is an estimate, use 'estimated: ... (grade: C)' format.
- Use Provenance::Citation.valid?(value) to check before the write and reject with a user-facing validation message.
- Make the citation field required upstream (model validation or form required attribute).
Example fix
# before Provenance::Citation.parse!(params[:source]) # after raise ArgumentError, "source is required" if params[:source].to_s.strip.empty? Provenance::Citation.parse!(params[:source])
Defensive patterns
Strategy: validation
Validate before calling
Provenance::Citation.valid?(value) # false when blank; check before writing
Type guard
def valid_citation?(value) = !value.to_s.strip.empty? && Provenance::Citation.valid?(value)
Try / catch
begin Provenance::Citation.parse!(source) rescue Provenance::Citation::InvalidError => e errors.add(:source, e.message) # feed message back to the agent/user end
Prevention
- Make the citation field required in forms and model validations.
- In agent prompts, demand a source string for every emitted value and reject outputs without one.
- Prefer Citation.valid? to probe, and use parse! only at the write boundary.
When it happens
Trigger: Calling Citation.parse!(nil), parse!(""), or parse!(" "); an agent/LLM omitting the source field when writing a ledger value; a form submitted with the citation field left empty.
Common situations: Agent pipeline where the model returned no source; optional form field treated as skippable; default nil passed through a data-import path.
Related errors
- source citation must be #{MAX_LENGTH} characters or fewer
- estimated values must start with the exact prefix #{ESTIMATE
- reliability grade must be one of #{GRADES.join(", ")} (got #
- source citation does not match #{grammar}
- source citation must name the document it came from
AI-assisted analysis of we-promise/sure@e69894adb9 (2026-08-21).
Data as JSON: /api/errors/bd4170c7ee56c8bc.
Report an issue: GitHub.