---
id: 10096
title: '[bug] GraphqlService.query discards partial data when GraphQL returns errors — breaks aliased batch queries'
state: CLOSED
labels:
  - bug
  - ai
  - architecture
assignees:
  - neo-gpt
createdAt: '2026-04-19T12:20:43Z'
updatedAt: '2026-06-03T09:22:28Z'
githubUrl: 'https://github.com/neomjs/neo/issues/10096'
author: tobiu
commentsCount: 0
parentIssue: null
subIssues: []
subIssuesCompleted: 0
subIssuesTotal: 0
blockedBy: []
blocking: []
closedAt: '2026-06-03T09:22:28Z'
---
# [bug] GraphqlService.query discards partial data when GraphQL returns errors — breaks aliased batch queries

## Context

`ai/mcp/server/github-workflow/services/GraphqlService.mjs:102-105` throws immediately if the GraphQL response contains an `errors` field, even when `data` is partially populated:

```javascript
if (json.errors) {
    logger.error('GitHub API returned errors:', json.errors);
    throw new Error(`GitHub API error: ${json.errors.map(e => e.message).join(', ')}`);
}
```

GraphQL's spec explicitly allows **partial data alongside per-field errors**. When an aliased batch query asks for N issues and one alias happens to reference a PR instead of an Issue, GitHub returns:
- `data.repository.issue42: { ... valid ... }`
- `data.repository.issue43: null` (the bad one)
- `errors: [{"message": "Could not resolve to an Issue with the number of 43", ...}]`

Our service discards the populated `data` for the other 99 aliases and throws. Downstream: the entire batch fails, even though 99 issues were successfully resolved.

## Reproducer

Discovered during PR #10093 verification:

```bash
node --input-type=module -e "
import {GH_Config} from './ai/services.mjs';
import GraphqlService from './ai/mcp/server/github-workflow/services/GraphqlService.mjs';
import {buildIssueTotalsBatchQuery} from './ai/mcp/server/github-workflow/services/queries/issueQueries.mjs';
const q = buildIssueTotalsBatchQuery([10090, 10091]); // 10091 is a PR
await GraphqlService.query(q, {owner:'neomjs', repo:'neo'}, true);
"
# Error: GitHub API error: Could not resolve to an Issue with the number of 10091.
# (even though 10090's data was populated in the response)
```

## Impact

Today this is latent because `metadata.issues` excludes PRs by contract. But every future aliased-batch query inherits this fragility — a single stale/converted reference will blackhole a whole batch of legitimate lookups. `detectStaleCommentsCounts` (introduced in #10092 / PR #10093) is one such consumer; more will follow as the InvalidationDetector pattern (#10094 if filed) expands.

## The Ask

Soften error handling to honor GraphQL's partial-data semantics:

1. On `errors` + populated `data`: log errors as warnings, return `{data, errors}`.
2. On `errors` + empty `data`: throw as today (hard failure, nothing to return).

Keep `strict: true` as the default parameter for back-compat. Callers that want graceful semantics (batch queries) opt in via `strict: false`.

## Acceptance Criteria

- [ ] `GraphqlService.query` accepts `options.strict` (default `true`)
- [ ] `strict: false` → logs GraphQL errors as warnings, returns `{data, errors}` when `data` has any non-null fields
- [ ] `detectStaleCommentsCounts` opts into `strict: false` — a bad alias no longer kills the whole batch
- [ ] Playwright spec for both modes: strict throws on any error; non-strict returns populated data + errors array
- [ ] JSDoc explains the strict/non-strict semantics and when to pick each

## Origin Session ID
`d9eb5e76-5430-45f7-b3ea-8600664d28f9`

Related: #10092 / PR #10093 (where this was exposed).

## Timeline

- 2026-04-19T12:20:45Z @tobiu added the `bug` label
- 2026-04-19T12:20:45Z @tobiu added the `ai` label
- 2026-04-19T12:20:45Z @tobiu added the `architecture` label
- 2026-04-19T21:53:35Z @tobiu cross-referenced by PR #10111
- 2026-05-18T17:59:53Z @neo-gpt cross-referenced by #11585
- 2026-06-03T00:00:56Z @neo-gpt assigned to @neo-gpt
- 2026-06-03T00:04:12Z @neo-gpt cross-referenced by PR #12400
- 2026-06-03T09:22:28Z @tobiu referenced in commit `a56a444` - "fix(ai): preserve GraphQL partial data in non-strict mode (#10096) (#12400)

Co-authored-by: tobiu <tobiasuhlig78@gmail.com>"
- 2026-06-03T09:22:29Z @tobiu closed this issue

