Skip to content

Conversation

Copy link
Contributor

Copilot AI commented Jan 19, 2026

Fix tab-set crash with invalid children

Fixes #243

Summary

This PR fixes a ValueError: not enough values to unpack (expected 2, got 1) crash that occurred when a .. tab-set:: directive contained invalid content (non-tab-item children).

Changes Made

1. Modified TabSetDirective.run_with_defaults() in sphinx_design/tabs.py (lines 38-53):

  • Changed from break to continue to warn about ALL invalid children, not just the first one
  • Added filtering to remove invalid children from tab_set.children
  • Valid tab-item directives are preserved in a new list and reassigned

2. Added defensive validation in TabSetHtmlTransform.run() in sphinx_design/tabs.py (lines 247-256):

  • Added check to skip non-tab-item children that may have slipped through
  • Added validation to ensure tab-item has exactly 2 children before unpacking
  • Logs appropriate warnings for malformed directives

3. Added comprehensive test in tests/test_misc.py:

  • Tests that tab-set with invalid children does not crash
  • Verifies warnings are properly logged
  • Confirms valid tab items are still processed and rendered correctly

Behavior After Fix

Before: Sphinx-design crashed with ValueError when encountering invalid content in a tab-set
After: Sphinx-design logs warnings for each invalid child and continues to render valid tab-items

Example input with invalid content:

.. tab-set::

   .. tab-item:: A
      A content

   foo  <-- Invalid content

   .. tab-item:: B
      B content

Result: Both valid tabs (A and B) render correctly, and a warning is logged for the invalid "foo" content.

Visual Verification

The fix was manually tested with a document containing invalid content between tab items:

Tab A rendered correctly
Tab B rendered correctly

All three valid tab items render and function correctly despite invalid content in the source.

Tests

All 110 tests pass, including the new test specifically for this issue:

  • test_tab_set_with_invalid_children - New test reproducing and validating the fix
  • ✅ All existing tests continue to pass
  • ✅ All pre-commit hooks pass

Checklist

  • Understand the issue and explore the codebase
  • Create tests to reproduce the ValueError bug
  • Fix TabSetDirective.run_with_defaults() to filter invalid children
  • Add defensive validation in TabSetHtmlTransform.run()
  • Run tests to verify the fix (110/110 passed)
  • Verify build and lint pass
  • Manual verification with visual test
  • Fix pre-commit formatting issues
Original prompt

Issue

Fixes #243

Sphinx-design crashes with a ValueError: not enough values to unpack (expected 2, got 1) when a .. tab-set:: directive contains something other than .. tab-item:: directives.

Reproduction

Tab Test document
=================

.. tab-set::

   .. tab-item:: A

      A content

   foo  <-- This line causes the crash

   .. tab-item:: B

      B content

Root Cause

The problem is in sphinx_design/tabs.py:

  1. In TabSetDirective.run_with_defaults() (lines 38-47): When a non-tab-item child is found, the code logs a warning but only breaks after the first invalid child. It does NOT remove the invalid children from tab_set.children.

  2. In TabSetHtmlTransform.run() (line 244): The code assumes all children are valid tab-item components with exactly 2 children:

    tab_label, tab_content = tab_item.children

    When an invalid child (like a text node) is encountered, it doesn't have 2 children, causing the unpacking error.

Required Fix

1. Modify TabSetDirective.run_with_defaults() in sphinx_design/tabs.py:

Change the loop that validates children to:

  • Use continue instead of break to warn about ALL invalid children, not just the first
  • Filter out invalid children so only valid tab-item components remain in tab_set.children

The current code:

for item in tab_set.children:
    if not is_component(item, "tab-item"):
        LOGGER.warning(
            f"All children of a 'tab-set' "
            f"should be 'tab-item' [{WARNING_TYPE}.tab]",
            location=item,
            type=WARNING_TYPE,
            subtype="tab",
        )
        break
    if "sync_id" in item.children[0]:
        item.children[0]["sync_group"] = self.options.get("sync-group", "tab")
return [tab_set]

Should become:

valid_children = []
for item in tab_set.children:
    if not is_component(item, "tab-item"):
        LOGGER.warning(
            f"All children of a 'tab-set' "
            f"should be 'tab-item' [{WARNING_TYPE}.tab]",
            location=item,
            type=WARNING_TYPE,
            subtype="tab",
        )
        continue  # Skip invalid children instead of breaking
    if "sync_id" in item.children[0]:
        item.children[0]["sync_group"] = self.options.get("sync-group", "tab")
    valid_children.append(item)

tab_set.children = valid_children
return [tab_set]

2. Add defensive validation in TabSetHtmlTransform.run() in sphinx_design/tabs.py:

In the loop at line 242, add a check before unpacking to handle any edge cases:

for idx, tab_item in enumerate(tab_set.children):
    if not is_component(tab_item, "tab-item"):
        continue  # Skip non tab-item children
    if len(tab_item.children) != 2:
        LOGGER.warning(
            f"Malformed 'tab-item' directive [{WARNING_TYPE}.tab]",
            location=tab_item,
            type=WARNING_TYPE,
            subtype="tab",
        )
        continue
    tab_label, tab_content = tab_item.children
    # ... rest of processing unchanged

Note: You'll need to import is_component at the top of the TabSetHtmlTransform.run() method if it's not already available in that scope (it should be available since it's imported from .shared).

Expected Behavior After Fix

  • Sphinx-design should NOT crash when invalid content is inside a tab-set
  • A warning should be logged for each invalid child
  • Valid tab-item directives should still be processed and rendered correctly
  • The warning should include accurate location information

This pull request was created from Copilot chat.


💡 You can make Copilot smarter by setting up custom instructions, customizing its development environment and configuring Model Context Protocol (MCP) servers. Learn more Copilot coding agent tips in the docs.

Co-authored-by: chrisjsewell <2997570+chrisjsewell@users.noreply.github.com>
Copilot AI changed the title [WIP] Fix ValueError in tab-set directive handling Fix ValueError crash when tab-set contains non-tab-item children Jan 19, 2026
Copilot AI requested a review from chrisjsewell January 19, 2026 21:36
Copy link
Member

@chrisjsewell chrisjsewell left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fix pre-commit

Co-authored-by: chrisjsewell <2997570+chrisjsewell@users.noreply.github.com>
Copy link
Contributor Author

Copilot AI commented Jan 19, 2026

Fix pre-commit

Fixed in 3654e94. Pre-commit hooks now pass (trailing whitespace and ruff formatting applied).

Copilot AI requested a review from chrisjsewell January 19, 2026 21:43
@chrisjsewell chrisjsewell marked this pull request as ready for review January 19, 2026 21:53
@chrisjsewell chrisjsewell merged commit aae4b81 into main Jan 19, 2026
23 checks passed
@chrisjsewell chrisjsewell deleted the copilot/fix-valueerror-in-tabset-directive branch January 19, 2026 22:02
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Crash when .. tab-set:: contains a non .. tab-item::

2 participants