Skip to content

fix(tickets): prevent /review and /describe crash on linked issues with sub-issues#2476

Merged
naorpeled merged 3 commits into
The-PR-Agent:mainfrom
naorpeled:fix/ticket-sub-issue-labels-2471
Jun 26, 2026
Merged

fix(tickets): prevent /review and /describe crash on linked issues with sub-issues#2476
naorpeled merged 3 commits into
The-PR-Agent:mainfrom
naorpeled:fix/ticket-sub-issue-labels-2471

Conversation

@naorpeled

Copy link
Copy Markdown
Member

Problem

When require_ticket_analysis_review is enabled (the default) and a PR references an issue that has sub-issues, both /review and /describe crash before any model call with:

UndefinedError: 'dynaconf.utils.boxing.DynaBox object' has no attribute 'labels'

This leaves a stuck "Preparing review…" placeholder that never resolves. /improve is unaffected because it doesn't call ticket extraction.

Root cause

In extract_tickets(), main-issue entries include a labels key but sub-issue entries (sub_issues_content) do not. extract_and_cache_pr_tickets() appends both into the same related_tickets list.

The reviewer/description prompts — and the token-counting pre-pass in token_handler.py — render this list under Environment(undefined=StrictUndefined). Under StrictUndefined, {% if ticket.labels %} on a label-less sub-issue raises UndefinedError instead of evaluating falsy, aborting the entire prompt render before the LLM request.

Fix

Two layers of defense:

  1. ticket_pr_compliance_check.py — add 'labels': "" to sub-issue entries so the key is always present.
  2. pr_reviewer_prompts.toml / pr_description_prompts.toml — guard with {% if ticket.labels is defined and ticket.labels %}, matching the existing ticket.requirements pattern, so the templates are robust against any future label-less entry.

Verification

Reproduced with the issue's pinned deps (dynaconf==3.2.4, Jinja2==3.1.6): the old template fragment crashes with UndefinedError on a label-less entry, while the new defensive template renders all entry shapes (with labels / missing key / empty string) cleanly.

Fixes #2471

…th sub-issues

Sub-issue entries built in extract_tickets() omitted the 'labels' key that
main-issue entries include. The reviewer/description prompts (and the
token_handler pre-pass) render related_tickets under StrictUndefined, so
accessing the missing ticket.labels raised UndefinedError, aborting the
prompt render before any model call.

Add an empty 'labels' key to sub-issue entries and make both templates
defensive with 'is defined and', matching the existing ticket.requirements
guard.

Fixes The-PR-Agent#2471
@github-actions github-actions Bot added the bug label Jun 26, 2026
@qodo-free-for-open-source-projects

Copy link
Copy Markdown
Contributor

PR Summary by Qodo

fix(tickets): avoid StrictUndefined crashes when sub-issues lack labels
🐞 Bug fix ⚙️ Configuration changes 🕐 10-20 Minutes

Grey Divider

Description

• Ensure sub-issue ticket entries always include a labels field during extraction.
• Make reviewer/description Jinja templates resilient to missing ticket.labels under
 StrictUndefined.
• Prevent /review and /describe from aborting before any model call when issues have sub-issues.
Diagram

graph TD
  A[/"/review & /describe"/] --> B["Ticket extraction (ticket_pr_compliance_check.py)"] --> C["related_tickets list"] --> D["Prompt render (pr_*_prompts.toml, StrictUndefined)"] --> E["LLM request"]
Loading
High-Level Assessment

The following are alternative approaches to this PR:

1. Normalize ticket schema via a typed model (dataclass/Pydantic)
  • ➕ Single authoritative schema for main issues vs sub-issues
  • ➕ Enforces presence/defaults for optional fields (labels/requirements/etc.)
  • ➕ Makes template context more predictable across providers
  • ➖ More refactor than necessary for a targeted bug fix
  • ➖ Introduces runtime/validation overhead and more code touchpoints
2. Template-only mitigation using Jinja defaults (e.g., `ticket.labels|default('')`)
  • ➕ No changes to extraction logic
  • ➕ Keeps all robustness concerns localized to prompts
  • ➖ Easy to miss in other templates/consumers (e.g., token counting pre-pass)
  • ➖ Doesn’t improve the actual data consistency of related_tickets
3. Relax StrictUndefined for prompt rendering
  • ➕ Prevents crashes for any missing fields without per-field guards
  • ➖ Hides real prompt-data bugs and can silently degrade prompt quality
  • ➖ Weakens existing defensive design that likely relies on StrictUndefined to catch issues early

Recommendation: Keep the PR’s two-layer approach (data shaping + template guards). It preserves StrictUndefined’s early-bug-detection value while ensuring the related_tickets list is schema-consistent and templates remain robust against future label-less entries.

Files changed (3) +4 / -3

Bug fix (3) +4 / -3
pr_description_prompts.tomlGuard ticket label rendering against undefined 'ticket.labels' +1/-1

Guard ticket label rendering against undefined 'ticket.labels'

• Updates the Related Ticket Info template to check 'ticket.labels is defined' before accessing it. Prevents StrictUndefined from raising when a ticket entry lacks the 'labels' key.

pr_agent/settings/pr_description_prompts.toml

pr_reviewer_prompts.tomlMake reviewer prompt label section StrictUndefined-safe +1/-1

Make reviewer prompt label section StrictUndefined-safe

• Adds an 'is defined' guard around the 'ticket.labels' conditional in the reviewer prompt template. This avoids pre-render crashes when 'related_tickets' contains sub-issue entries without labels.

pr_agent/settings/pr_reviewer_prompts.toml

ticket_pr_compliance_check.pyAdd default empty 'labels' to extracted sub-issue ticket dicts +2/-1

Add default empty 'labels' to extracted sub-issue ticket dicts

• Ensures sub-issue entries appended to 'related_tickets' include a 'labels' key (empty string). This keeps the ticket shape consistent with main-issue entries and prevents template rendering failures under StrictUndefined.

pr_agent/tools/ticket_pr_compliance_check.py

Sub-issues are regular GitHub issues and can carry labels, so extract them
the same way main-issue labels are extracted rather than discarding the data.
Falls back to an empty string when there are none, keeping the key present
for the StrictUndefined template render.
@qodo-free-for-open-source-projects

qodo-free-for-open-source-projects Bot commented Jun 26, 2026

Copy link
Copy Markdown
Contributor

Code Review by Qodo

🐞 Bugs (0) 📘 Rule violations (0) 📎 Requirement gaps (0)

Grey Divider

Great, no issues found!

Qodo reviewed your code and found no material issues that require review

Grey Divider

  • Author self-review: I have reviewed the code review findings, and addressed the relevant ones.

Previous review results

Review updated until commit cda33fd

Results up to commit 0cd6ee8


🐞 Bugs (0) 📘 Rule violations (0) 📎 Requirement gaps (0)

Great, no issues found!

Qodo reviewed your code and found no material issues that require review

Qodo Logo

@qodo-free-for-open-source-projects

Copy link
Copy Markdown
Contributor

Code review by qodo was updated up to the latest commit 22ec72b

@qodo-free-for-open-source-projects

Copy link
Copy Markdown
Contributor

Code review by qodo was updated up to the latest commit cda33fd

@naorpeled naorpeled merged commit 74e4d98 into The-PR-Agent:main Jun 26, 2026
5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

/review and /describe crash with UndefinedError: '...DynaBox object' has no attribute 'labels' when a linked issue has sub-issues

1 participant