function handleErrorResponse()

in sdk/core/core-client/src/deserializationPolicy.ts [226:323]


function handleErrorResponse(
  parsedResponse: FullOperationResponse,
  operationSpec: OperationSpec,
  responseSpec: OperationResponseMap | undefined,
  options: RequiredSerializerOptions,
): { error: RestError | null; shouldReturnResponse: boolean } {
  const isSuccessByStatus = 200 <= parsedResponse.status && parsedResponse.status < 300;
  const isExpectedStatusCode: boolean = isOperationSpecEmpty(operationSpec)
    ? isSuccessByStatus
    : !!responseSpec;

  if (isExpectedStatusCode) {
    if (responseSpec) {
      if (!responseSpec.isError) {
        return { error: null, shouldReturnResponse: false };
      }
    } else {
      return { error: null, shouldReturnResponse: false };
    }
  }

  const errorResponseSpec = responseSpec ?? operationSpec.responses.default;

  const initialErrorMessage = parsedResponse.request.streamResponseStatusCodes?.has(
    parsedResponse.status,
  )
    ? `Unexpected status code: ${parsedResponse.status}`
    : (parsedResponse.bodyAsText as string);

  const error = new RestError(initialErrorMessage, {
    statusCode: parsedResponse.status,
    request: parsedResponse.request,
    response: parsedResponse,
  });

  // If the item failed but there's no error spec or default spec to deserialize the error,
  // and the parsed body doesn't look like an error object,
  // we should fail so we just throw the parsed response
  if (
    !errorResponseSpec &&
    !(parsedResponse.parsedBody?.error?.code && parsedResponse.parsedBody?.error?.message)
  ) {
    throw error;
  }

  const defaultBodyMapper = errorResponseSpec?.bodyMapper;
  const defaultHeadersMapper = errorResponseSpec?.headersMapper;

  try {
    // If error response has a body, try to deserialize it using default body mapper.
    // Then try to extract error code & message from it
    if (parsedResponse.parsedBody) {
      const parsedBody = parsedResponse.parsedBody;
      let deserializedError;

      if (defaultBodyMapper) {
        let valueToDeserialize: any = parsedBody;
        if (operationSpec.isXML && defaultBodyMapper.type.name === MapperTypeNames.Sequence) {
          valueToDeserialize = [];
          const elementName = defaultBodyMapper.xmlElementName;
          if (typeof parsedBody === "object" && elementName) {
            valueToDeserialize = parsedBody[elementName];
          }
        }
        deserializedError = operationSpec.serializer.deserialize(
          defaultBodyMapper,
          valueToDeserialize,
          "error.response.parsedBody",
          options,
        );
      }

      const internalError: any = parsedBody.error || deserializedError || parsedBody;
      error.code = internalError.code;
      if (internalError.message) {
        error.message = internalError.message;
      }

      if (defaultBodyMapper) {
        (error.response! as FullOperationResponse).parsedBody = deserializedError;
      }
    }

    // If error response has headers, try to deserialize it using default header mapper
    if (parsedResponse.headers && defaultHeadersMapper) {
      (error.response! as FullOperationResponse).parsedHeaders =
        operationSpec.serializer.deserialize(
          defaultHeadersMapper,
          parsedResponse.headers.toJSON(),
          "operationRes.parsedHeaders",
        );
    }
  } catch (defaultError: any) {
    error.message = `Error "${defaultError.message}" occurred in deserializing the responseBody - "${parsedResponse.bodyAsText}" for the default response.`;
  }

  return { error, shouldReturnResponse: false };
}