# Error Handling in Pipeline Code

## No silent swallowing

Never write `except Exception: pass` or `except Exception: return`. Every except block must either:
- Log at WARNING or higher with `exc_info=True`
- Re-raise after cleanup
- Return a clearly documented sentinel value with at least DEBUG logging

## Protect ast.parse() calls

`ast.parse()` raises `SyntaxError` on malformed input. Always wrap it:

```python
try:
    tree = ast.parse(source)
except SyntaxError:
    log.warning("Failed to parse %s", path)
    return None  # or skip this file
```

## XML/TOML parsing

Always use `recover=True` for lxml XMLParser. Always wrap tomlkit.parse() in try/except. Log parsing failures at WARNING, not DEBUG -- config parsing failures matter.

## Format consistency: client-server boundary

The AI service returns markdown-fenced code blocks. Every endpoint response must be parsed with `CodeStringsMarkdown.parse_markdown_code()` before using the code. This is handled in `_refinement.py:_parse_candidate()` and `_candidate_gen.py:generate_candidates()`.

Pattern to follow (from `pipeline/_candidate_gen.py:83-91`):

```python
parsed = CodeStringsMarkdown.parse_markdown_code(c.code)
if not parsed.code_strings:
    continue
plain_code = "\n\n".join(cs.code for cs in parsed.code_strings)
```
