krahets/hello-algo · error · IndexError

両端キューが空です

Error message

両端キューが空です

What it means

This IndexError (Japanese: '両端キューが空です' = 'deque is empty') is raised by LinkedListDeque.pop(is_front) (linkedlist_deque.py:66) when _size == 0. pop() reads _front.val or _rear.val; on an empty deque both pointers are None, so accessing .val would raise AttributeError — the guard prevents that. pop_first()/pop_last() delegate here, so the exception surfaces through both.

Source

Thrown at ja/codes/python/chapter_stack_and_queue/linkedlist_deque.py:66

        else:
            # node を連結リストの末尾に追加
            self._rear.next = node
            node.prev = self._rear
            self._rear = node  # 末尾ノードを更新する
        self._size += 1  # キューの長さを更新

    def push_first(self, num: int):
        """キュー先頭にエンキュー"""
        self.push(num, True)

    def push_last(self, num: int):
        """キュー末尾にエンキュー"""
        self.push(num, False)

    def pop(self, is_front: bool) -> int:
        """デキュー操作"""
        if self.is_empty():
            raise IndexError("両端キューが空です")
        # キュー先頭からの取り出し
        if is_front:
            val: int = self._front.val  # 先頭ノードの値を一時保存
            # 先頭ノードを削除
            fnext: ListNode | None = self._front.next
            if fnext is not None:
                fnext.prev = None
                self._front.next = None
            self._front = fnext  # 先頭ノードを更新する
        # キュー末尾からの取り出し
        else:
            val: int = self._rear.val  # 末尾ノードの値を一時保存
            # 末尾ノードを削除
            rprev: ListNode | None = self._rear.prev
            if rprev is not None:
                rprev.next = None
                self._rear.prev = None
            self._rear = rprev  # 末尾ノードを更新する

View on GitHub (pinned to 69932aed18)

Solutions

  1. Guard with `if not dq.is_empty(): dq.pop_first()` (or pop_last).
  2. Drain via `while not dq.is_empty():`.
  3. Track the number of outstanding elements externally and never pop beyond it.
  4. Wrap pop_first/pop_last in try/except IndexError for tolerant consumers.

Example fix

// before
val = dq.pop_first()  # IndexError when empty

// after
val = dq.pop_first() if not dq.is_empty() else None
Defensive patterns

Strategy: validation

Validate before calling

if not dq.is_empty():
    val = dq.pop_first()
# pop_last() delegates to the same pop() — guard identically

Type guard

def deque_has_element(dq: LinkedListDeque) -> bool:
    return not dq.is_empty()

Try / catch

try:
    val = dq.pop_first()
except IndexError:
    val = None

Prevention

When it happens

Trigger: Calling pop_first() or pop_last() on a freshly constructed LinkedListDeque (size 0). Calling pop more times than push. The linked-list deque is unbounded (no capacity limit), so 'empty' is the only failure mode from pop.

Common situations: Draining both ends in a sliding-window or palindrome-style algorithm and over-popping. Treating None pointers as safe-to-deref. Holding references after the deque was emptied elsewhere.

Related errors


AI-assisted analysis of krahets/hello-algo@69932aed18 (2026-08-13). Data as JSON: /api/errors/7938671e988f4058. Report an issue: GitHub.