Atomic Work Item task-list toggle raises on an out-of-range stale source position

Summary

A task-list toggle created from an earlier Work Item description can refer to a line that no longer exists after another client replaces or shortens the description. Instead of following the existing recoverable concurrent-edit path, the update raises while comparing the missing line.

Steps to reproduce

  1. Enable the experimental work_items_task_list_toggle feature.
  2. Create a Work Item with:
Intro

- [ ] Task 1
  1. Client A loads the Work Item and retains:
lineSource: "- [ ] Task 1"
lineSourcepos: "3:4-3:4"
  1. Client B replaces the description with Intro, so the original third line no longer exists.
  2. Client A submits the original task-list toggle with checked: true.

Current behavior

TaskListToggleService raises before its normal stale-input protocol can run:

NoMethodError: undefined method 'chomp' for nil

In the request-level regression, the Work Item GraphQL mutation produced a top-level internal error with no mutation data instead of the existing concurrent-edit response. This report does not characterize the HTTP status.

Expected behavior

The stale toggle should:

  • not modify the shortened description;
  • not toggle another line;
  • use the existing concurrent-edit recovery path;
  • return current Work Item state with the normal conflict error.

Root cause

current Markdown
→ split into lines
→ stale source line index is out of range
→ array lookup returns nil
→ chomp is called on nil
→ TaskListToggleService cannot return its normal falsey result
→ existing StaleObjectError recovery is bypassed

Why this is a bug

An existing in-range stale line_source already produces a normal unsuccessful toggle. IssuableBaseService converts that falsey result into the task-toggle-specific ActiveRecord::StaleObjectError. Mutations::WorkItems::Update catches that condition and returns a recoverable “Someone edited this…” response with current Work Item state.

A concurrently removed line is the same stale-input class and should follow that existing contract.

Affected versions

Dynamically reproduced on master commit:

44fa09d18de27fb46f9bbbc5e0037b662ad53ec7

The same unsafe implementation was observed statically in GitLab 19.3.1. A second stable runtime reproduction was not performed.

The Work Item input is experimental, introduced in 19.2, and guarded by the default-disabled work_items_task_list_toggle feature flag.

Regression evidence

Before:
service regression → NoMethodError

After:
TaskListToggleService full spec → 26 examples, 0 failures
Work Item update mutation full spec → 131 examples, 0 failures
RuboCop → clean
git diff --check → clean

Additional notes

A bounded public search found no obvious duplicate or open equivalent fix; private scope is unknown.

Origin issue: #582358 (closed) Atomic API introduction: !244520 (merged) Rollout tracking: #605619 (closed)

Edited by 🤖 GitLab Bot 🤖