pydo icon indicating copy to clipboard operation
pydo copied to clipboard

415 Unsupported Media Type for projects.delete function in _operations.py

Open ovidsec opened this issue 1 year ago • 2 comments

Using the example python for the Delete an Existing Project API call results in a 415 Unsupported Media Type error (https://docs.digitalocean.com/reference/api/api-reference/#operation/projects_delete) e.g.:

resp = client.projects.delete(project_id="038ea76a-cae8-4c26-a1c6-3476e7a94ceb")

As shown in the following error output:

╰─λ python digitalOceanDroplet.py 
Request:  <HttpRequest [DELETE], url: 'https://api.digitalocean.com/v2/projects/038ea76a-cae8-4c26-a1c6-3476e7a94ceb'>
Current Headers:  {'Accept': 'application/json'}
Server Response: <HttpResponse: 415 Unsupported Media Type, Content-Type: application/json; charset=utf-8>
Traceback (most recent call last):
... ... ... ...
  File "digitalOceanDroplet.py", line 48, in deleteDOProject
    resp = client.projects.delete(project_id="038ea76a-cae8-4c26-a1c6-3476e7a94ceb")
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File ".../lib/python3.12/site-packages/azure/core/tracing/decorator.py", line 94, in wrapper_use_tracer
    return func(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^
  File ".../lib/python3.12/site-packages/pydo/operations/_operations.py", line 145454, in delete
    raise HttpResponseError(response=response)
azure.core.exceptions.HttpResponseError: Operation returned an invalid status 'Unsupported Media Type'

In file _operations.py, the project DELETE functionality is outlined, with the request sent and response handled at (https://raw.githubusercontent.com/digitalocean/pydo/refs/heads/main/src/pydo/operations/_operations.py):

145439        _request.url = self._client.format_url(_request.url)
... ... ... 
145448        response = pipeline_response.http_response                                                                                    
145449
145450        if response.status_code not in [204, 404, 412]:
145451          if _stream:
145452              response.read()  # Load the body in memory and close the socket
145453          map_error(status_code=response.status_code, response=response, error_map=error_map)  # type: ignore
145454          raise HttpResponseError(response=response)      
... ... ... 

Temporary Workaround

As a hacky workaround, forcing the Content-Type header prior to the request within _operations.py with the following to force the Content-Type HTTP Header allows the API call to successfully process.

... ... ... 
145439         _request.url = self._client.format_url(_request.url)
                      print('Request: ', _request)                                            # <- optional print for visibility
                      print('Current Headers: ', _request.headers)                            # <- optional print for visibility
                      _request.headers['Content-Type'] = 'application/json; charset=utf-8'    # <- Update HTTP header to force Content-Type
                      print('Forced Content-Type addition headers:', _request.headers)        # <- optional print updated headers
145441         _stream = False
145442         pipeline_response: PipelineResponse = (
145443              self._client._pipeline.run(  # pylint: disable=protected-acces144581         
145444                  _request, stream=_stream, **kwargs
145445             )
145446         )
145447         
145448         response = pipeline_response.http_response
                      print('Server Response:', response)                                     # <- optional print for visibility of server response
145450         if response.status_code not in [204, 404, 412]:
145451              if _stream:
145452                 response.read()  # Load the body in memory and close the socket
145453              map_error(status_code=response.status_code, response=response, error_map=error_map)  # type: ignore
145454              raise HttpResponseError(response=response)
... ... ...

204 is returned confirming successful deletion:

[🔴] × python digitalOceanDroplet.py 
Request:  <HttpRequest [DELETE], url: 'https://api.digitalocean.com/v2/projects/038ea76a-cae8-4c26-a1c6-3476e7a94ceb'>
Current Headers:  {'Accept': 'application/json'}
Forced Content-Type addition headers: {'Accept': 'application/json', 'Content-Type': 'application/json; charset=utf-8'}
Server Response: <HttpResponse: 204 No Content, Content-Type: application/json; charset=utf-8>

Content-Type is defined in multiple places throughout the _operations.py file but not the delete projects function; it's likely better defined elsewhere.

ovidsec avatar Oct 29 '24 11:10 ovidsec

Hi i would like to work on this could you assign me

revanth2802 avatar Oct 07 '25 17:10 revanth2802

Hi i would like to work on this issue . Please assign it to me @ovidsec

ProgrammingPirates avatar Oct 08 '25 08:10 ProgrammingPirates