Graphify-Labs/graphify · error · ValueError

outcome must be one of {OUTCOMES}, got {outcome!r}

Error message

outcome must be one of {OUTCOMES}, got {outcome!r}

What it means

Raised by graphify's Q&A memory writer (save query/Q&A results as markdown in the memory dir) when the optional outcome argument is non-None but not one of the allowed tuple OUTCOMES = ('useful', 'dead_end', 'corrected'). The outcome is a work-memory signal written to both the YAML frontmatter and an '## Outcome' body section, so only the three canonical values round-trip deterministically through `graphify reflect`.

Source

Thrown at graphify/ingest.py:295

    memory_dir: Path,
    query_type: str = "query",
    source_nodes: list[str] | None = None,
    outcome: str | None = None,
    correction: str | None = None,
) -> Path:
    """Save a Q&A result as markdown so it gets extracted into the graph on next --update.

    Files are stored in memory_dir (typically graphify-out/memory/) with YAML frontmatter
    that graphify's extractor reads as node metadata. This closes the feedback loop:
    the system grows smarter from both what you add AND what you ask.

    ``outcome`` (one of :data:`OUTCOMES`) and ``correction`` are optional work-memory
    signals: they are written both to the frontmatter (so `graphify reflect` can
    aggregate them deterministically) and to an ``## Outcome`` body section (so the
    signal round-trips into the graph on the next semantic re-extraction).
    """
    if outcome is not None and outcome not in OUTCOMES:
        raise ValueError(f"outcome must be one of {OUTCOMES}, got {outcome!r}")

    memory_dir = Path(memory_dir)
    memory_dir.mkdir(parents=True, exist_ok=True)

    now = datetime.now(timezone.utc)
    slug = re.sub(r"[^\w]", "_", question.lower())[:50].strip("_")
    filename = f"query_{now.strftime('%Y%m%d_%H%M%S')}_{slug}.md"

    frontmatter_lines = [
        "---",
        f'type: "{query_type}"',
        f'date: "{now.isoformat()}"',
        f'question: "{_yaml_str(question)}"',
        'contributor: "graphify"',
    ]
    if outcome:
        frontmatter_lines.append(f'outcome: "{_yaml_str(outcome)}"')
    if correction:

View on GitHub (pinned to 7fe58b0b0f)

Solutions

  1. Use one of the exact values: 'useful', 'dead_end', or 'corrected' (lowercase, underscore)
  2. Pass None (or omit the argument) when there is no outcome signal
  3. Map external enums at the call site: {'positive': 'useful', 'negative': 'dead_end', 'fix': 'corrected'}

Example fix

# before
save_qa("How do hooks work?", answer, outcome="helpful")
# ValueError: outcome must be one of ('useful', 'dead_end', 'corrected')

# after
save_qa("How do hooks work?", answer, outcome="useful")
Defensive patterns

Strategy: type-guard

Validate before calling

from graphify.ingest import OUTCOMES  # ('useful', 'dead_end', 'corrected')

if outcome is not None and outcome not in OUTCOMES:
    raise SystemExit(f"invalid outcome {outcome!r}; choose from {OUTCOMES}")

Type guard

from typing import Literal
from graphify.ingest import OUTCOMES

Outcome = Literal["useful", "dead_end", "corrected"]

def is_valid_outcome(value: object) -> bool:
    """Narrow arbitrary input to the canonical outcome tuple."""
    return value is None or (isinstance(value, str) and value in OUTCOMES)

Try / catch

try:
    save_qa(question, answer, outcome=outcome)
except ValueError as e:
    if "outcome must be one of" in str(e):
        outcome = "corrected" if correction else "useful"  # sanitize to a default
        save_qa(question, answer, outcome=outcome, correction=correction)
    else:
        raise

Prevention

When it happens

Trigger: Calling the save-QA function (e.g. graphify's API for recording query outcomes) with outcome='yes', 'bad', 'USEFUL' (case-sensitive), or any free-form string outside the tuple; None is explicitly allowed.

Common situations: Scripting the memory loop with ad-hoc labels; UI wrappers mapping their own enum ('positive'/'negative') onto outcome; case mismatches; passing 0/1 integers.

Related errors


AI-assisted analysis of Graphify-Labs/graphify@7fe58b0b0f (2026-08-14). Data as JSON: /api/errors/c62ff04bbca1c513. Report an issue: GitHub.