Skip to content

issues list/search may hit "Query too complex" at the default limit (CompleteIssueFields carries four unbounded connections) #286

Description

@iamfj

Summary

CompleteIssueFields carries four unbounded nested connections. Linear's complexity estimator charges an unbounded connection at its default page size (50) per parent row, so issues list and issues search — both defaulting to -l 50 — are priced the same way projects list was in #276, which #284 has just fixed for the projects domain only.

This is the same defect class as #276/#283, in a different (and more frequently used) domain.

Evidence

The unbounded connections in CompleteIssueFields (graphql/queries/issues.graphql):

  • labels (~line 29)
  • children (~line 50)
  • relations (~line 57)
  • inverseRelations

Consumers that spread it at the root with a user-controlled first:

  • GetIssues (graphql/queries/issues.graphql:235) ← issues list, default -l 50 (src/commands/issues.ts:604)
  • FilteredSearchIssues (graphql/queries/issues.graphql:357) ← issues search, default -l 50 (src/commands/issues.ts:638)

The arithmetic

#284 measured, against the live API, that each issue selected through CompleteIssueFields prices at ~260 (consistent with 4 connections × 50 rows × 1.3). That measurement is what justified lowering projects read --issues-first from 50 to 25 there — empirically it passes at 35 and fails at 40, i.e. a ceiling around 10000/263 ≈ 38 issues.

Applying the same model to issues list at its default limit of 50 gives ~13,000 against the 10,000 budget.

What needs checking first

The ~260 figure was measured for issues nested under a project, not for issues at the query root. Before any code change, someone with a real workspace should run:

linearis issues list
linearis issues search "<term>"
  • If they fail — this is a live P0-class bug on the most-used command in the tool, and the fix mirrors fix(projects): bound project query connections to avoid complexity limit #284: bound the four connections inside CompleteIssueFields. Note that fragment is shared far more widely than the project fragments were, so this is a cross-domain behaviour change (silent truncation of labels/children/relations per issue) and wants its own measurement pass rather than a copy of the 25s.
  • If they succeed — the estimator prices root connections differently from nested ones, and the cost model documented in graphql/queries/projects.graphql and src/services/project-service.ts should get a footnote saying so, since it currently reads as universal.

Either outcome is worth having written down.

Related, same shape

src/commands/issues.ts:1471 reads CompleteIssueFields.labels (unbounded, so an implicit 50) and writes the result back as a full-replacement labelIds. An issue with more than 50 labels would therefore lose labels 51+ on issues update --label-mode add. Unreachable in practice, but it is exactly the read-modify-write hazard #284 moved the projects domain off of (its lean pre-read now fetches 250), so the two domains are now inconsistent. Worth fixing in the same pass.

Context

Split out of the review of #284, which deliberately scoped itself to the projects domain. Nothing here regresses because of that PR — this defect predates it.

Refs #284
Refs #276
Refs #283

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions