tui/persona/registry: PersonaRegistry.get() raises unhandled yaml.YAMLError/ValidationError on corrupted persona file #10375

Open
opened 2026-04-18 09:15:35 +00:00 by HAL9000 · 1 comment
Owner

Metadata

  • Commit message: fix(tui/persona/registry): catch yaml.YAMLError and ValidationError in PersonaRegistry.get()
  • Branch: fix/persona-registry-get-error-handling

Background and Context

PersonaRegistry.get() in src/cleveragents/tui/persona/registry.py does not catch yaml.YAMLError or pydantic.ValidationError, unlike list_personas() which handles these gracefully. A corrupted persona YAML file causes an unhandled exception that crashes the TUI on every input submission. This is inconsistent with list_personas() which gracefully skips invalid files.

get() is called from PersonaState.active_persona() → _refresh_persona_bar() in app.py, which is called on every input submission. A corrupted persona file will crash the TUI on every keystroke.

Expected Behavior

get() should return None for corrupted or schema-invalid persona files, consistent with list_personas() which logs a warning and skips invalid files.

Acceptance Criteria

  • PersonaRegistry.get() catches (yaml.YAMLError, ValidationError) and returns None
  • A warning is logged when a corrupted file is encountered (consistent with list_personas())
  • TUI does not crash when a persona YAML file is corrupted
  • All TDD tests from #10372 pass
  • No regression in existing persona loading behavior

Subtasks

  • Add try/except block in PersonaRegistry.get() wrapping yaml.safe_load() and Persona.model_validate()
  • Log a warning on exception (consistent with list_personas())
  • Return None on exception
  • Verify all TDD tests from #10372 pass
  • Verify no regression in existing tests

Bug Report

Summary

PersonaRegistry.get() does not catch yaml.YAMLError or pydantic.ValidationError, unlike list_personas() which handles these gracefully. A corrupted persona YAML file causes an unhandled exception that crashes the TUI on every input submission.

Code Evidence

File: src/cleveragents/tui/persona/registry.py

list_personas() (line 104-113) correctly handles errors:

def list_personas(self) -> list[Persona]:
    ...
    for file in sorted(self.personas_dir.glob("*.y*ml")):
        try:
            raw = yaml.safe_load(file.read_text(encoding="utf-8")) or {}
            if not isinstance(raw, dict):
                continue
            personas.append(Persona.model_validate(raw))
        except (yaml.YAMLError, ValidationError) as exc:
            _logger.warning("Skipping invalid persona file %s: %s", file, exc)
    return personas

get() (line 116-123) does NOT handle errors:

def get(self, name: str) -> Persona | None:
    file = self.persona_path(name)
    if not file.exists():
        return None
    raw = yaml.safe_load(file.read_text(encoding="utf-8")) or {}  # ← unhandled yaml.YAMLError
    if not isinstance(raw, dict):
        return None
    return Persona.model_validate(raw)  # ← unhandled ValidationError

Call Chain

get() is called from PersonaState.active_persona() → _refresh_persona_bar() in app.py, which is called on every input submission. A corrupted persona file will crash the TUI on every keystroke.

Steps to Reproduce

  1. Create a persona via the TUI
  2. Manually corrupt the persona YAML file (e.g., ~/.config/cleveragents/personas/default.yaml)
  3. Submit any input in the TUI
  4. The TUI crashes with yaml.YAMLError or pydantic.ValidationError

Expected Behavior

get() should return None for corrupted or schema-invalid persona files, consistent with list_personas() which logs a warning and skips invalid files.

Actual Behavior

get() raises an unhandled exception, crashing the TUI.

Fix Path

def get(self, name: str) -> Persona | None:
    file = self.persona_path(name)
    if not file.exists():
        return None
    try:
        raw = yaml.safe_load(file.read_text(encoding="utf-8")) or {}
        if not isinstance(raw, dict):
            return None
        return Persona.model_validate(raw)
    except (yaml.YAMLError, ValidationError) as exc:
        _logger.warning("Skipping invalid persona file %s: %s", file, exc)
        return None

Blocked By

#10372

Definition of Done

This issue should be closed when:

  • PersonaRegistry.get() catches (yaml.YAMLError, ValidationError) and returns None
  • A warning is logged when a corrupted file is encountered
  • All TDD tests from #10372 pass
  • No regression in existing persona loading behavior
  • The fix is merged to the main branch

Automated by CleverAgents Bot
Agent: new-issue-creator

## Metadata - **Commit message:** `fix(tui/persona/registry): catch yaml.YAMLError and ValidationError in PersonaRegistry.get()` - **Branch:** `fix/persona-registry-get-error-handling` ## Background and Context `PersonaRegistry.get()` in `src/cleveragents/tui/persona/registry.py` does not catch `yaml.YAMLError` or `pydantic.ValidationError`, unlike `list_personas()` which handles these gracefully. A corrupted persona YAML file causes an unhandled exception that crashes the TUI on every input submission. This is inconsistent with `list_personas()` which gracefully skips invalid files. `get()` is called from `PersonaState.active_persona()` → `_refresh_persona_bar()` in `app.py`, which is called on every input submission. A corrupted persona file will crash the TUI on every keystroke. ## Expected Behavior `get()` should return `None` for corrupted or schema-invalid persona files, consistent with `list_personas()` which logs a warning and skips invalid files. ## Acceptance Criteria - [ ] `PersonaRegistry.get()` catches `(yaml.YAMLError, ValidationError)` and returns `None` - [ ] A warning is logged when a corrupted file is encountered (consistent with `list_personas()`) - [ ] TUI does not crash when a persona YAML file is corrupted - [ ] All TDD tests from #10372 pass - [ ] No regression in existing persona loading behavior ## Subtasks - [ ] Add try/except block in `PersonaRegistry.get()` wrapping `yaml.safe_load()` and `Persona.model_validate()` - [ ] Log a warning on exception (consistent with `list_personas()`) - [ ] Return `None` on exception - [ ] Verify all TDD tests from #10372 pass - [ ] Verify no regression in existing tests ## Bug Report ### Summary `PersonaRegistry.get()` does not catch `yaml.YAMLError` or `pydantic.ValidationError`, unlike `list_personas()` which handles these gracefully. A corrupted persona YAML file causes an unhandled exception that crashes the TUI on every input submission. ### Code Evidence **File:** `src/cleveragents/tui/persona/registry.py` `list_personas()` (line 104-113) correctly handles errors: ```python def list_personas(self) -> list[Persona]: ... for file in sorted(self.personas_dir.glob("*.y*ml")): try: raw = yaml.safe_load(file.read_text(encoding="utf-8")) or {} if not isinstance(raw, dict): continue personas.append(Persona.model_validate(raw)) except (yaml.YAMLError, ValidationError) as exc: _logger.warning("Skipping invalid persona file %s: %s", file, exc) return personas ``` `get()` (line 116-123) does NOT handle errors: ```python def get(self, name: str) -> Persona | None: file = self.persona_path(name) if not file.exists(): return None raw = yaml.safe_load(file.read_text(encoding="utf-8")) or {} # ← unhandled yaml.YAMLError if not isinstance(raw, dict): return None return Persona.model_validate(raw) # ← unhandled ValidationError ``` ### Call Chain `get()` is called from `PersonaState.active_persona()` → `_refresh_persona_bar()` in `app.py`, which is called on every input submission. A corrupted persona file will crash the TUI on every keystroke. ### Steps to Reproduce 1. Create a persona via the TUI 2. Manually corrupt the persona YAML file (e.g., `~/.config/cleveragents/personas/default.yaml`) 3. Submit any input in the TUI 4. The TUI crashes with `yaml.YAMLError` or `pydantic.ValidationError` ### Expected Behavior `get()` should return `None` for corrupted or schema-invalid persona files, consistent with `list_personas()` which logs a warning and skips invalid files. ### Actual Behavior `get()` raises an unhandled exception, crashing the TUI. ### Fix Path ```python def get(self, name: str) -> Persona | None: file = self.persona_path(name) if not file.exists(): return None try: raw = yaml.safe_load(file.read_text(encoding="utf-8")) or {} if not isinstance(raw, dict): return None return Persona.model_validate(raw) except (yaml.YAMLError, ValidationError) as exc: _logger.warning("Skipping invalid persona file %s: %s", file, exc) return None ``` ### Blocked By #10372 ## Definition of Done This issue should be closed when: - `PersonaRegistry.get()` catches `(yaml.YAMLError, ValidationError)` and returns `None` - A warning is logged when a corrupted file is encountered - All TDD tests from #10372 pass - No regression in existing persona loading behavior - The fix is merged to the main branch --- **Automated by CleverAgents Bot** Agent: new-issue-creator
HAL9000 added this to the v3.7.0 milestone 2026-04-18 09:23:44 +00:00
Author
Owner

[GROOMED] Quality Analysis Report

Issue Validity: ✅ VALID & ACTIONABLE

This is a legitimate Priority/Critical bug affecting TUI stability. The issue is well-documented with:

  • Clear problem statement: PersonaRegistry.get() lacks error handling for corrupted YAML files
  • Code evidence showing the inconsistency with list_personas()
  • Reproducible steps and impact analysis
  • Proposed fix path with acceptance criteria
  • Proper blocking relationship (#10372)

Label Verification: ✅ COMPLETE

Current Labels:

  • ✅ Priority/Critical (id: 858) — Correct
  • ✅ State/Verified (id: 847) — UPDATED (was State/Unverified)
  • ✅ Type/Bug (id: 849) — Correct

Status: All required labels present. State transitioned from Unverified → Verified.

Milestone Assignment: ✅ ASSIGNED

  • Assigned to: v3.7.0 (M8: TUI Implementation)
  • Rationale: This is a critical TUI bug affecting persona registry functionality, which is core to the TUI milestone scope

Issue Quality Assessment

Aspect Status Notes
Problem Statement ✅ Excellent Clear, specific, reproducible
Code Evidence ✅ Complete Shows both broken and correct patterns
Impact Analysis ✅ High Crashes TUI on every keystroke if persona corrupted
Acceptance Criteria ✅ Well-defined 5 clear criteria with subtasks
Blocking Dependencies ✅ Documented Blocked by #10372 (TDD tests)
Fix Path ✅ Provided Includes exact code changes needed

Grooming Actions Completed

  1. ✅ Verified issue is legitimate and actionable
  2. ✅ Confirmed all required labels present
  3. ✅ Transitioned from State/Unverified → State/Verified
  4. ✅ Assigned to v3.7.0 (TUI Implementation) milestone
  5. ✅ Flagged as Priority/Critical for immediate attention

Recommendations

  • For Implementor: This issue is ready for implementation once #10372 (TDD tests) is complete
  • For Reviewer: Ensure error handling matches list_personas() pattern exactly
  • For QA: Test with manually corrupted persona YAML files in ~/.config/cleveragents/personas/

Summary

Issue #10375 is a valid, well-documented Priority/Critical bug that has been successfully groomed and is ready for the development backlog. The issue demonstrates excellent quality with clear acceptance criteria, code evidence, and a proposed fix path. It is now assigned to v3.7.0 (TUI Implementation) milestone and transitioned to State/Verified status.


Automated by CleverAgents Bot
Supervisor: Grooming | Agent: grooming-pool-supervisor

## [GROOMED] Quality Analysis Report ### Issue Validity: ✅ VALID & ACTIONABLE This is a **legitimate Priority/Critical bug** affecting TUI stability. The issue is well-documented with: - Clear problem statement: `PersonaRegistry.get()` lacks error handling for corrupted YAML files - Code evidence showing the inconsistency with `list_personas()` - Reproducible steps and impact analysis - Proposed fix path with acceptance criteria - Proper blocking relationship (#10372) ### Label Verification: ✅ COMPLETE **Current Labels:** - ✅ Priority/Critical (id: 858) — Correct - ✅ State/Verified (id: 847) — **UPDATED** (was State/Unverified) - ✅ Type/Bug (id: 849) — Correct **Status:** All required labels present. State transitioned from Unverified → Verified. ### Milestone Assignment: ✅ ASSIGNED - **Assigned to:** v3.7.0 (M8: TUI Implementation) - **Rationale:** This is a critical TUI bug affecting persona registry functionality, which is core to the TUI milestone scope ### Issue Quality Assessment | Aspect | Status | Notes | |--------|--------|-------| | Problem Statement | ✅ Excellent | Clear, specific, reproducible | | Code Evidence | ✅ Complete | Shows both broken and correct patterns | | Impact Analysis | ✅ High | Crashes TUI on every keystroke if persona corrupted | | Acceptance Criteria | ✅ Well-defined | 5 clear criteria with subtasks | | Blocking Dependencies | ✅ Documented | Blocked by #10372 (TDD tests) | | Fix Path | ✅ Provided | Includes exact code changes needed | ### Grooming Actions Completed 1. ✅ Verified issue is legitimate and actionable 2. ✅ Confirmed all required labels present 3. ✅ Transitioned from State/Unverified → State/Verified 4. ✅ Assigned to v3.7.0 (TUI Implementation) milestone 5. ✅ Flagged as Priority/Critical for immediate attention ### Recommendations - **For Implementor:** This issue is ready for implementation once #10372 (TDD tests) is complete - **For Reviewer:** Ensure error handling matches `list_personas()` pattern exactly - **For QA:** Test with manually corrupted persona YAML files in ~/.config/cleveragents/personas/ ### Summary Issue #10375 is a **valid, well-documented Priority/Critical bug** that has been successfully groomed and is ready for the development backlog. The issue demonstrates excellent quality with clear acceptance criteria, code evidence, and a proposed fix path. It is now assigned to v3.7.0 (TUI Implementation) milestone and transitioned to State/Verified status. --- **Automated by CleverAgents Bot** Supervisor: Grooming | Agent: grooming-pool-supervisor
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
cleveragents/cleveragents-core#10375
No description provided.