cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 
dalvarado-nonem
Community Participant

Getting a 422 (Unprocessable entity) error when attempting to execute grade passback

Jump to solution

I'm trying to get Canvas grade passbook to work.  I'm submitting to the endpoint

https://canvas.instructure.com/api/lti/v1/tools/208981/grade_passback

with the Authorization header

OAuth oauth_body_hash="6MfU9ZcvzMc6XPbdd1PNwiTF1d8=",oauth_nonce="ZiKbzAr8iYsoaUvEFKVV8t1tSrLnhfL6",oauth_signature="0J0XinNaZycfv0UoHcSpCJGYm6M=",oauth_consumer_key="OBSCURED",realm="",oauth_version="1.0",oauth_timestamp="1525367433",oauth_signature_method="HMAC-SHA1"

and the Content-Type header of "application/xml".  Below is teh body of the request...

<?xml version="1.0" encoding="UTF-8"?>

<imsx_POXEnvelopeRequest xmlns="http://www.imsglobal.org/services/ltiv1p1/xsd/imsoms_v1p0">

  <imsx_POXHeader>

    <imsx_POXRequestHeaderInfo>

      <imsx_version>V1.0</imsx_version>

      <imsx_messageIdentifier>3vG8bzKSKnQznI6Hk9alccMTlvHu0SqQ</imsx_messageIdentifier>

    </imsx_POXRequestHeaderInfo>

  </imsx_POXHeader>

  <imsx_POXBody>

    <replaceResultRequest>

      <resultRecord>

        <sourcedGUID>

          <sourcedId>208981-1290816-8386147-13666019-c6d8c979d6aa1b99f7b8b4947f6135f474e1111a</sourcedId>

        </sourcedGUID>

        <result>

          <resultScore>

            <language>en</language>

            <textString>0.08333333333333333</textString>

          </resultScore>

  <resultData>

            <text>text data for canvas submission</text>

          </resultData>

        </result>

      </resultRecord>

    </replaceResultRequest>

  </imsx_POXBody>

</imsx_POXEnvelopeRequest>

This is resulting in a  422 Unprocessable Entity error.  Can someone shed light on what this error means and what I can do to fix it?

28 Replies
dalvarado-nonem
Community Participant

We get the lis_result_sourcedid and the endpoint when launching the assignment in Canvas as a student.  However the gradepassback is an implementation of the IMS' replace result specification -- Learning Tools Interoperability v1.1 Implementation Guide | IMS Global Learning Consortium  .  As such, there is no being logged in to Canvas so you don't have a role specified.  The call is initiated from a third party system (our proprietary gradebook) to Canvas' gradebook.

Can you point me to any cases where someone was getting a 422 and then changed some stuff to get it resolved?  Uncle Google is not leading me to those results.

Thanks, - Dave

I think we might have been talking at cross-purposes with the role, I just meant their role in the course, which you have clarified as student.

I just tried a few things with our test tool and I could get a 422 if I changed the http method or if I changed the Content-Type header.  So I'd double-check these.  Other things I tried like incorrect xml or missing body hash didn't give a 422.

If you search "422" using the community site's search, you will see what has come up here before.

pklove
Community Champion

I can also get a 422 if the signature string is wrong, or if I use an incorrect secret.

dalvarado-nonem
Community Participant

I'll try and mess around with the signatures to see if that is the issue but regarding the 422 errors occurring on this forum, this is what i get when I search "422" -- https://community.canvaslms.com/search.jspa?q=422  .  None of these threads refers to grade passback.  The only one that comes up is this one.  Please correct me if there was a specific thread you were referring to (and possibly post a link to it Smiley Wink ). Thanks, - Dave

422 is not a Canvas or Gradebook error it is an HTTP status code. It's unlikely, someone would trigger (and post) the same 422 problem you are having. HTTP response status codes - HTTP | MDN 

My suggestion would be to take your code back to the start and just try making calls, and putting your code back together until it fails. Can you supply the code where you are making the POST request?

422 is certainly an HTTP status code but it is being returned from teh Canvas servers in response to our request.  The Canvas development team programmed that code when certain conditions arose.  What are those conditions?  My question is what are they referring to specifically by an "Unprocessable entity."  If others have had the same problem (e.g. got a 422 response when submitting a gradepassback call), I'm interested in what the error and resolution were.

Also we can certainly "start from scratch," as you suggest, but our LMS is interacting fine via gradepassback with other LMSs (e.g. Schoology) so at the moment we are focussing on specific issues relating to Canvas.  If our code was not working on any LMS, we may consider starting all over again.

dalvarado-nonem
Community Participant

Hey Peter, Do you work for Canvas?  To answer one of your other questions, we set the "Content-Type" header to "application/xml".  This was stated in the documentation but sometimes docs get old/out-dated so perhaps there are other headers we need to set that are not documented?

jpoulos
Instructure
Instructure

 @dalvarado-nonem  This is due to your authorization header being invalid. Have you tried omitting the oauth_body_hash? It doesn't look like it's required in the oauth header spec. I also wonder if there something going on with your double quotes, maybe the need to be escaped?

I found the error on the Canvas backend that shows that not only is the signature mismatching (the generated_signature is what Canvas thinks it should be), but it seems that perhaps your quotes are throwing Canvas in it's error report generation (notice the key value pairs are all mixed up). I've never seen an error report scrambled up like this:

account: Free For Teachers
category: BasicLTI::BasicOutcomes::Unauthorized

": oauth_nonce 
"0J0XinNaZycfv0UoHcSpCJGYm6M: " 
HTTP_HOST: canvas.instructure.com 
HTTP_USER_AGENT: Apache-HttpClient/4.5.3 (Java/1.8.0_60) 
PATH_INFO: /api/lti/v1/tools/208981/grade_passback 
QUERY_STRING: ? 
REMOTE_ADDR: <redacted>
REQUEST_METHOD: POST 
REQUEST_URI: https://canvas.instructure.com/api/lti/v1/tools/208981/grade_passback 
SERVER_NAME: canvas.instructure.com 
ZiKbzAr8iYsoaUvEFKVV8t1tSrLnhfL6: oauth_signature 
error_class: OAuth::Unauthorized 
format: application/json 
generated_signature: W4R0QhJNPDd16A9s3gski8Jn/eY= 
oauth_body_hash: "6MfU9ZcvzMc6XPbdd1PNwiTF1d8 
oauth_consumer_key: <redacted> 
oauth_signature_method: HMAC-SHA1 
oauth_timestamp: 1525367433 
oauth_version: 1.0 
query_parameters: {} 
realm: 
request_parameters: {} 

dalvarado-nonem
Community Participant

Hey Jesse!  You're on the case, I'm stoked.  One question I have is can you see in your logs what the raw signature is prior to Canvas calculating its signature for comparison?  That may answer the question of whether the oauth_body_hash param is needed or not.

jpoulos
Instructure
Instructure

Unfortunately, no, we don't log the base string used to generate the signature. I'm pretty sure we use the header values you send, the http method, and the post body to build the base string. Fundamentally speaking, however, you should be able to use the same library you (I'm assuming) are using to validate the signature for the initial LTI request for your tool to also sign the POST request back to Canvas. I guess that would depend on the capabilities of that lib though...

I still suspect something weird going on with either the inclusion of the oauth_body_hash, or the quotes, but I could be wrong.