Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Please explain how to get the response body when an exception is thrown. #4456

Closed
hroe opened this issue Jun 18, 2019 — with docs.microsoft.com · 8 comments
Closed
Labels
area-utility Area - Microsoft.PowerShell.Utility module

Comments

Copy link

hroe commented Jun 18, 2019

We need this for better error handling for POST requests to https://api.powerbi.com/v1.0/myorg/groups.
For http 400 errors, Fiddler revealed that response body has useful explanation, such as:

  • {'error':{'code':'DuplicateGroupNameError','pbi.error':{'code':'DuplicateGroupNameError','parameters':{},'details':[]}}}
  • {'error':{'code':'ADGraphGroupOperationFailedQuotaExceeded','pbi.error':{'code':'ADGraphGroupOperationFailedQuotaExceeded','parameters':{},'details':[],'exceptionCulprit':1}}}

Document Details

Do not edit this section. It is required for docs.microsoft.com ➟ GitHub issue linking.

@sdwheeler sdwheeler added the area-utility Area - Microsoft.PowerShell.Utility module label Jun 18, 2019
@sdwheeler
Copy link
Contributor

You have to wrap it in a try/catch block. You may have to dig a few layers deep in the exception to find the root cause.

try {
    Invoke-RestMethod ... your parameters here ... 
} catch {
    # Dig into the exception to get the Response details.
    Write-Host "StatusCode:" $_.Exception.Response.StatusCode.value__ 
    Write-Host "StatusDescription:" $_.Exception.Response.StatusDescription
}

@sdwheeler
Copy link
Contributor

@markekraus Is the body of the response available in the exception record?

Copy link
Contributor

@sdwheeler that code will output the code and the (generic) error message that gets printed to the console. For a 400 error for example, that will get you "Bad Request" But REST APIs generally send additional data in the body, which is what @hroe is referring to.
Because a non 2xx return code generates an exception, the cmdlet eats the data the API sends back (I would consider this a bug but this isn't the place for that).

The returned data is in the $error but you have to work to get at it:

$reader = New-Object System.IO.StreamReader($_.Exception.Response.GetResponseStream())
$reader.BaseStream.Position = 0
$reader.DiscardBufferedData()
$reader.ReadToEnd() | ConvertFrom-Json

@hroe
Copy link
Author

hroe commented Jun 21, 2019

@FISHMANPET @sdwheeler,
thanks for pointing this out.
I had to drop the |ConvertFrom-Json as this results in @{error=}
With only $reader.ReadToEnd I get access to the response body, e.g.:
{"error":{"code":"AddingAlreadyExistsGroupUserNotSupportedError","pbi.error":{"code":"AddingAlreadyExistsGroupUserNotSupportedError","parameters":{},"details":[]}}}

Thanks, Herman

@hroe hroe closed this as completed Jun 21, 2019
@FISHMANPET
Copy link
Contributor

for what it's worth, after doing some more digging, I discovered that in PS6 that data is properly read and included directly in the error, so you only need to do that to get the error data on 5.1 and below.

@ojgarciab
Copy link

ojgarciab commented Jul 28, 2021

@FISHMANPET is right:

try {
    Invoke-RestMethod ... your parameters here ... 
} catch {
    # New in PS6
    Write-Error -Message $_.ErrorDetails.Message
}

If JSON response is:

{
  "errors" : [ {
    "message" : "Product ID does not exists"
  } ]
}

You could get the message as follows:

try {
    Invoke-RestMethod ... your parameters here ... 
} catch {
    $response = $_.ErrorDetails.Message | ConvertFrom-Json
    Write-Error -Message $response.errors[0].message
}

ImfeldC added a commit to ImfeldC/CheckLMS that referenced this issue Apr 26, 2022
# '20220421': try/catch rest method call, read addtional data, see MicrosoftDocs/PowerShell-Docs#4456
@msrinivascharan
Copy link

@sdwheeler that code will output the code and the (generic) error message that gets printed to the console. For a 400 error for example, that will get you "Bad Request" But REST APIs generally send additional data in the body, which is what @hroe is referring to. Because a non 2xx return code generates an exception, the cmdlet eats the data the API sends back (I would consider this a bug but this isn't the place for that).

The returned data is in the $error but you have to work to get at it:

$reader = New-Object System.IO.StreamReader($_.Exception.Response.GetResponseStream())
$reader.BaseStream.Position = 0
$reader.DiscardBufferedData()
$reader.ReadToEnd() | ConvertFrom-Json

Thank you @FISHMANPET , it worked.

@Jaykul
Copy link
Contributor

Jaykul commented Dec 9, 2023

Nowadays this is even easier. in 7.4 you can use -SkipHttpErrorCheck if you know the API will return an error response you can parse, or just check the .Message on the error by simply doing something like this:

irm -Method Post http://localhost:8000/api/example -Err Fail
|| ConvertFrom-Json $Fail.Message

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area-utility Area - Microsoft.PowerShell.Utility module
Projects
None yet
Development

No branches or pull requests

6 participants