Skip to content

Json requestBody cannot be optional #1354

Closed

Description

@orelmaliach

Describe the bug
Generating an endpoint from an operation where requestBody has required: false (or required is unspecified) and an application/json content, still requires a body, despite it being optional.
Providing a None body with ...sync_detailed(body=None) will result in nil dereference in _kwargs["json"] = body.to_dict().
Providing an 'empty' body such as ...sync_detailed(body=RequestBody()) will result in an empty json object. i.e. {}, which is not desirable.

OpenAPI Spec File

openapi: 3.1.1
info:
  title: ""
  version: ""
paths:
  /request:
    post:
      operationId: request
      requestBody:
        required: false
        content:
          application/json:
            schema:
              type: object
      responses:
        "201":
          description: ""

Desktop (please complete the following information):

  • OS: macOS 15.7.1
  • Python version: 3.13.3
  • openapi-python-client version: 0.25.1

Additional context
I've described the bug for application/json request bodies, but it may exist for other content types as well.
Similarly, I provided an example using openAPI spec version 3.1.1, but it might be relevant for other versions as well.

Activity

  1. dbanty commented on Nov 5, 2025

    @dbanty
    Collaborator

    If the body is not required, that enables you to omit the parameter entirely, like sync_detailed().

    Passing any value there will try to set that value as the body. None becomes null, classes become objects, etc.

    The client also has a special UNSET value it uses as a sentinel to determine when a value hasn't been passed. If you need to, you can import that from types.py and pass it like sync_detailed(body=UNSET).

    The preference, though, is to not pass a value at all if it's not required and you don't need it.

  2. orelmaliach commented on Nov 5, 2025

    @orelmaliach
    Author

    Not passing any value results of course in TypeError: sync_detailed() missing 1 required positional argument: 'body'.
    And Unset fails when to_dict() is invoked on it in _get_kwargs.
    I generated a test client with above yaml. No custom config/templates, and result is same.

    (venv) ➜ cat request.py | grep -A5 sync_detailed
    def sync_detailed(
        *,
        client: Union[AuthenticatedClient, Client],
        body: RequestBody,
    ) -> Response[Any]:
        """
    

    Am I missing something?!

  3. reopened this on Nov 6, 2025
  4. dbanty commented on Nov 6, 2025

    @dbanty
    Collaborator

    Am I missing something?!

    Nope, you're right! The thing that works for every other type of input doesn't work for bodies 😱.

  5. dbanty commented on Nov 6, 2025

    @dbanty
    Collaborator

    I whipped up a potential fix in #1357, please give it a try and let me know if it works!

    Sorry for accidentally gaslighting you 😅

  6. orelmaliach commented on Nov 6, 2025

    @orelmaliach
    Author

    Your quick responses and resolution more than make up for it :)
    A quick test from my side looks good for both application/json and application/x-www-form-urlencoded content types!

  7. added a commit that references this issue on Dec 3, 2025
    49fa8fc
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

    🐞bugSomething isn't working

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions