Skip to content

fix(types): Literal[True] = True default on canceled fields silently destroys media buys when buyer omits the field #641

Description

@bokelley

Problem

Generated request types declare cancellation fields as:

```python
canceled: Annotated[
Literal[True],
Field(description='Cancel the entire media buy. Cancellation is irreversible...'),
] = True
```

The default `= True` means a buyer who omits `canceled` from the request gets it auto-set to `True` by Pydantic — i.e. the request is silently treated as a cancellation.

This is destructive: an `update_media_buy` call meant to change pacing or budget cancels the media buy if the caller forgot to include `canceled: false` (which can't be set to `false` anyway because the field is `Literal[True]`).

Affected fields

Four emissions across two conceptual fields:

File Class Field
`media_buy/update_media_buy_request.py` `UpdateMediaBuyRequest` `canceled`
`media_buy/package_update.py` `PackageUpdate` `canceled`
`bundled/media_buy/update_media_buy_request.py` `UpdateMediaBuyRequest` (bundled inline) `canceled`
`bundled/media_buy/update_media_buy_request.py` `PackageUpdate` (bundled inline) `canceled`

Response-side `canceled: bool | None = False` (e.g. `core/package.py:143`) is correct — that's a status indicator and the default is non-destructive.

Salesagent workaround

Salesagent applies an Optional-widening override on its side (`canceled: Literal[True] | None = None`) so the field is non-destructive when omitted. Every adopter has to do the same dance.

Proposed library fix

Change codegen output from:

```python
canceled: Annotated[Literal[True], Field(...)] = True
```

to:

```python
canceled: Annotated[Literal[True] | None, Field(...)] = None
```

Same wire shape (the field still only accepts `true` if present) but omission is no longer a cancellation. Mechanically the rewrite has two parts:

  1. Annotation: `Literal[True]` → `Literal[True] | None`
  2. Default: `= True` → `= None`

This is a separate fix class from #624 (Sequence widening). The right home is a new function in `scripts/post_generate_fixes.py`, scoped to the four emissions above (and any future cancel-style `Literal[True]` fields on request types — response status indicators stay as `bool | None = False`).

Severity

This is a footgun that silently destroys production state when a buyer omits a field. It's easy to hit accidentally because the field doesn't visually look like a destructive flag — there's no `destructive=True` annotation, no required-field error, just silent cancellation on omission.

Adopter impact

Once the SDK fix lands, salesagent (and any other adopter currently shipping the workaround) can drop their `canceled: Literal[True] | None = None` override.

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

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions