Skip to content

docs(issues): Mark issue update body fields as optional - #130348

Merged
BYK merged 1 commit into
masterfrom
docs/issue-update-body-optional-fields
Nov 7, 2026
Merged

BYK merged 1 commit into
masterfrom
docs/issue-update-body-optional-fields

Conversation

@sentry-junior

@sentry-junior sentry-junior Bot commented Nov 7, 2026 •

Copy link
Copy Markdown
Contributor

The OpenAPI schema for PUT /organizations/{org}/issues/{issue_id}/ (updateOrganizationIssue) and PUT /organizations/{org}/issues/ (updateOrganizationIssues) listed every GroupValidator field, and every statusDetails field, as required. The endpoints always validate with partial=True (validate_request in api/helpers/group_index/update.py), so a request only sends the fields it changes, for example {"status": "resolved"}.

This marks those fields required=False. Validation doesn't change, because partial=True already skipped the required check. Only the two operations above change in the generated schema. Their request body schemas lose the required lists, and the body itself is no longer marked required.

The Sentry CLI needs this to move its issue update calls onto the generated @sentry/api operations (getsentry/toolkit#2073). Today the generated body type makes every field mandatory, so a partial update doesn't typecheck.

Checked locally with make build-api-docs, pnpm run validate-api-examples, tests/apidocs, tests/sentry/issues/endpoints/test_group_details.py, GroupUpdateTest in test_organization_group_index.py, tests/sentry/api/helpers/test_group_index.py, prek and mypy. Under xdist, three snuba-backed GroupUpdateTest cases failed: test_resolve_with_integration, test_snooze_user_count and test_bulk_resolve. Run serially, they pass on this branch and on master.

via @BYK.

--

View Session [Sentry]

The single and bulk issue update endpoints always run GroupValidator with
partial=True, so a request only has to send the fields it changes. The
validators still declared every field as required, so the OpenAPI schema
listed all of them, and every statusDetails field, as required in the
request body. Generated clients such as @sentry/api then type every field
as required, so a body that only sets status or assignedTo fails to typecheck.

Mark the fields required=False so the docs match what the endpoints
accept. Validation is unchanged because partial=True already skipped the
required check.

Refs getsentry/toolkit#2073

Co-Authored-By: BYK <[email protected]>
@sentry-junior
sentry-junior Bot requested a review from a team as a code owner November 7, 2026 01:16
@github-actions github-actions Bot added the Scope: Backend Automatically applied to PRs that change backend components label Nov 7, 2026
@BYK
BYK merged commit 7274e5a into master Nov 7, 2026
80 of 81 checks passed
@BYK
BYK deleted the docs/issue-update-body-optional-fields branch November 7, 2026 01:29
BYK added a commit to getsentry/toolkit that referenced this pull request Nov 7, 2026
Stacked on #2073. That PR moves the CLI onto the generated `@sentry/api`
operations. This one fixes the cases where the CLI, not the API docs,
was wrong. The full list is in getsentry/sentry#130351. Where the 1.44.0
operation now matches, the call moves onto it here too.

Each fix was checked against the getsentry/sentry endpoint code.

### Moved onto generated operations
| Area | Fix | Operation |
| --- | --- | --- |
| `alert issues list/view` | Filter workflows by `project` (the endpoint
ignores `projectSlug`) and send `id` as a number |
`listOrganizationWorkflows` (×2) |
| `code-mappings upload` | Send the bulk body in snake_case:
`default_branch`, `stack_root`, `source_root` |
`bulkUpsertOrganizationCodeMappings` |
| `explore`, `dashboard view` tables | Type `dataset` as a public Events
dataset. Explore still falls back to `errors`, and unmapped widget types
still render as unsupported | `listOrganizationEvents` (×2) |
| `issue view` and other org-scoped issue lookups | Send only the
`collapse` values the details endpoint reads (`release`, `stats`,
`tags`). It ignored `lifetime`/`filtered`/`unhandled`, and the detail
response keeps those fields either way. The short-ID endpoint still gets
every value | `getOrganizationIssue` |
| `issue view` replay lookup | Send `data_source=errors`. `events` isn't
a value the endpoint accepts | `getOrganizationReplayCount` |
| `issue explain/plan` | Drop `mode=explorer`, which the autofix
endpoint never reads | `startOrganizationIssueAutofix` (×2),
`getOrganizationIssueAutofixState` |

### Fixed, but still on the helper
- **`issue merge`**: now sends `{merge: true}` with numeric IDs.
`updateOrganizationIssues` marks every body field required until
getsentry/sentry#130348 lands.
- **`trace view`**: no longer sends `project` or `limit`, since the
endpoint reads neither. It stays on the helper until
getsentry/sentry#130349 documents `timestamp`. An unknown project in
`trace view org/project/<id>` still fails as before.
- **Dashboard and explore time series**: get the same typed `dataset`,
but stay on the helper until #130349 fixes `yAxis`/`interval`.
- **AI conversations list**: untouched, because it's waiting on
getsentry/sentry#130350 (`sort`).

### Kept on purpose
- **`replay list`** keeps requesting `info_ids` and `warning_ids`. The
server computes them and `replay list --json` prints them, so dropping
them would change the output. `fetchReplayPage` stays on the helper, and
a comment says why.

### Behavior notes
- On the moved calls, errors use the SDK wording already used by the
moved calls in #2073 and by the metric alert path, e.g. `Failed to list
issue alert rules: 403 Forbidden`. They no longer start with `API
request failed:`, and they no longer have an `Endpoint:` line. Status
codes and the 401/403 enrichment are unchanged.
- Existing bug, not fixed here: `trace view org/project/<id>` prints
"Filtered to project", but the trace endpoint has returned spans from
every project since getsentry/sentry#87314.
- Docs gap: with `returnIds=true`, the replay-count response maps each
issue ID to a list of replay IDs. The documented schema describes
counts. The CLI keeps validating that response with its own schema.

### Verification
- `pnpm run tsc` and `pnpm run lint` pass.
- CLI tests: 12884 pass and 5 fail. All 5 are the sandbox-only
permission tests that fail on `main` too (`completions` ×2, `upgrade`
acquireLock, `db/resilient` readonly, `dsn/code-scanner`).
- Unit tests were updated or added for each changed request shape,
including the new `test/lib/api/code-mappings.test.ts`.
- API discovery no longer lists the moved call sites.

<!-- junior-request-attribution:start -->
via @BYK.
<!-- junior-request-attribution:end -->

<!-- junior-session-footer:start -->
<!-- junior-conversation-id:agent%3A80220b9d4c297e2a971f05dcb03af515 -->

--

[View
Session](https://junior-prod.sentry.dev/conversations/agent%3A80220b9d4c297e2a971f05dcb03af515)
[[Sentry]](https://sentry.sentry.io/explore/conversations/agent%3A80220b9d4c297e2a971f05dcb03af515/?project=4510944073809921)

<!-- junior-session-footer:end -->

Co-authored-by: sentry-junior[bot] <264270552+sentry-junior[bot]@users.noreply.github.com>
Co-authored-by: BYK <[email protected]>
BYK pushed a commit to getsentry/toolkit that referenced this pull request Nov 7, 2026
…2078)

Next step after #2073 and #2075, which moved the CLI onto the generated
`@sentry/api` operations. `@sentry/api` 1.46.0 includes the API docs
fixes from getsentry/sentry#130348, #130349 and #130350, so six more
call sites now match their generated operation. This PR bumps the
package and moves them.

### Moved onto generated operations
| Command(s) | Call | Operation | Unblocked by |
| --- | --- | --- | --- |
| `issue resolve/unresolve/archive`, `feedback resolve/spam/…`
(org-scoped) | `updateIssueStatus` | `updateOrganizationIssue` |
sentry#130348 (body fields no longer all required) |
| `issue merge` | `mergeIssues` | `updateOrganizationIssues` with
numeric `id`s and `{merge: true}` | sentry#130348 |
| `dashboard view` chart widgets | `queryWidgetTimeseries` |
`listOrganizationEventsTimeseries` | sentry#130349 (`yAxis` array,
`interval` int or duration) |
| `explore` time series | `queryEventsTimeSeries` |
`listOrganizationEventsTimeseries` | sentry#130349 |
| `agent-conversation list` | `listConversations` |
`listOrganizationAiConversations` with `sort` | sentry#130350 |
| `trace view`, `span view`, `log view` | `getDetailedTrace` |
`getOrganizationTrace` with `timestamp` | sentry#130349 |

Trace meta already used `getOrganizationTraceMeta` and doesn't send
`timestamp`, so nothing changes there.

### Behavior notes
- Responses are validated exactly as before:
`EventsTimeseriesResponseSchema` for widgets and
`ConversationListItemSchema` for conversations. The explore time series
and trace detail responses were not validated before and still aren't.
- `issue merge` still turns a 204 (no matching issues) into the same
friendly error, and still clears each affected issue's cross-origin
cache.
- `agent-conversation list --sort` is now typed with the endpoint's sort
enum. The command's sort values are a subset of it.
- Errors on the moved calls use the SDK wording, as in #2073 and #2075,
e.g. `Failed to update issue: 403 Forbidden`. Status codes and the
401/403 enrichment are unchanged.
- The 1.46.0 regen also changes `uniqueValues`/`key`/`name` descriptions
in the generated `issue` skill reference, which is committed here.
Typecheck is otherwise unaffected.

### Remaining `apiRequest*` call sites and raw fetches
Details for each are in getsentry/sentry#130351.

**Not in the public schema** (needs a getsentry/sentry API docs
decision):
- `organizations.ts:66`, `projects.ts:576/591`: region lookups
- `users.ts:21`: current user
- `trials.ts:30/70`: trials list/start
- `org-auth-tokens.ts:77`: delete org auth token
- `dashboards.ts:201/235`: dashboard revisions/restore
- `issues.ts:329`: unscoped `GET /issues/{id}/`
- `issues.ts:632`: legacy unscoped `PUT /issues/{id}/`
- `logs.ts:486`: logs query
- `traces.ts:225`: trace-items detail (experimental)
- `releases.ts:425`: release set-commits
- `preprod-artifacts.ts:283/449`: build/snapshot upload
- Raw fetches: `getSharedIssue` (`issues.ts`) and `openSnapshotArchive`
(`preprod-artifacts.ts`)

**Dynamic request identity / transport:**
- `auth.ts:17`
- `org-auth-tokens.ts:37/59`
- `preprod-artifacts.ts:508/526`: snapshot downloads

**Kept on purpose:**
- `replays.ts:201`: `replay list` keeps requesting
`info_ids`/`warning_ids` because `--json` prints them (see #2075).

The Oxlint rule that bans the helpers comes last, after these are
resolved.

### Verification
- `pnpm install --frozen-lockfile` passes with the committed lockfile.
- `pnpm run tsc` and `pnpm run lint` pass.
- CLI tests: 12919 pass and 5 fail. All 5 are the sandbox-only
permission tests that also fail on `main` (`completions` ×2, `upgrade`
acquireLock, `db/resilient` readonly, `dsn/code-scanner`).
- The dashboard time series tests now mock
`listOrganizationEventsTimeseries`. I added an org-scoped
`updateIssueStatus` test. The conversation, explore and trace tests run
at the fetch layer and pass unchanged.
- API discovery no longer lists the moved call sites.

<!-- junior-request-attribution:start -->
via @BYK.
<!-- junior-request-attribution:end -->

<!-- junior-session-footer:start -->
<!-- junior-conversation-id:agent%3A80220b9d4c297e2a971f05dcb03af515 -->

--

[View
Session](https://junior-prod.sentry.dev/conversations/agent%3A80220b9d4c297e2a971f05dcb03af515)
[[Sentry]](https://sentry.sentry.io/explore/conversations/agent%3A80220b9d4c297e2a971f05dcb03af515/?project=4510944073809921)

<!-- junior-session-footer:end -->

Co-authored-by: sentry-junior[bot] <264270552+sentry-junior[bot]@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Scope: Backend Automatically applied to PRs that change backend components

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant