Skip navigation
All Places > Blackboard Developer Community > Blackboard Learn Developers > Blog > Author: mkauffman
1 2 3 4 Previous Next

Blackboard Learn Developers

58 Posts authored by: mkauffman

Unable to save 3471ee11-a65e-40d9-b54d-93129189f09f" We've had several reports of this. You will get this message when trying to register an LTI 1.3 tool on a Learn system when there is already an LTI tool on the same Learn system with the same domain.


One example: You register MyCoolRestApp on with the domain: Now you register another, MyCoolLTI13App on on with the same domain: You go to a Learn system and register MyCoolRestApp as an LTI 1.3 tool provider, then you try to register MyCoolLTI13App as an LTI 1.3 tool provider. You will see the "Unable to save..." message because you can not register two LTI apps on the same Learn system that have the same domain.

   If you see the message "Field must be in the format of an https URL" when registering an App on with multiple Tool Redirect URLs, remove the space.

We often hear about this message "The Tool Provider has been disabled by the System Administrator"  The usual cause is that one of the 3 LTI switches is disabled. There are 3 places you need to enable LTI: (1) at the tool level, (2) at the course/organization level, and (3) at the LTI Global Properties level. Screenshots follow.


Administrator Panel -> Tools & Utilities section -> Tools


In a Course/Organization, Start at the Left Nav Menu


Administrator Panel -> Integrations section -> LTI Tool Providers -> Manage Global Properties

I've had reports of this happening on a system upgrade, or sometimes when a course is copied. I've not heard of a means to keep this from occurring but can tell you one thing to always check. Check that LTI is enabled at the course level.


I've often had questions like "Where do I find the Q4 2018 Learn Installer?" This brief video shows you how to use Behind the Blackboard to find the installation package you are looking for.

This is a follow on to the recent blog post about HttpClient .jar files. I'm writing because another vendor was using the Axis libraries we had in the classpath pre 3700.5.0. Those are gone too.


Always bundle all 3rd-party non-Blackboard .jars with your B2 and depend on those. Then the the B2 you ship won't break when Blackboard removes or upgrades the 3rd-party libraries in Learn that are/were on the classpath. And, be certain to keep the libraries your Building Block depends on up to date.


In general: Third party developers should include, and keep up-to-date, all non-Blackboard-authored jars that they need in their .war files, even if one that they need happens to exist in the class path already.  Blackboard will be upgrading or removing these jars as required and without notice.


I've had the question asked several times now so it deserves a blog post. The short answer to the question is to use Managed Placements. Reference this Blackboard Help article. This help article is also helpful. Here is a video demonstration

"Unable to launch link. The Tool Provider has been disabled by the System Administrator," even after enabling LTI and the specific tool in system-level Tools and the LTI global settings are correct. The issue is that LTI is not enabled at the course level. Watch this video to see the setting that causes the issue and how to fix it. 


The short version: Left Nav: Customization -> Tool Availability  -> Check the LTI Checkbox -> Hit submit 

I'm writing this to inform B2 developers that Blackboard has removed the Apache Commons HttpClient 3.x library from /usr/local/blackboard/systemlib in Blackboard Learn 3700.5.0. We are using HttpClient 4.x in Learn versions 3700.5.0 and later. 3700.5.0 has been in client-test since the 11th of June and went into production this last week on July 11. If your B2 depended on the HttpClient library that was in /usr/local/blackboard/systemlib and now gone, you will need to update it accordingly.


Here is a helpful blog post on the process of moving from HttpClient 3.x to 4.x Note that this is NOT meant to be a cookbook on what to do, only an example of the types of things you might need to do. You will need to do your own research as a Java developer to make the changes to update to the HttpClient you do with.


In general: Third party developers should include, and keep up-to-date, all non-Blackboard-authored jars that they need in their .war files, even if one that they need happens to exist in the class path already.  Blackboard will be upgrading or removing these jars as required and without notice.


With the current pace of our SaaS deliveries, remember: Test early. Test often.

This blog post contains links to a complete demonstration of setting up and using Shout out to Scott Hurrey & Eric Preston and his team (everyone you see on the commit list at the repo!)  for all their work and help with this.


First things first: Read, and understand, the specification. We can't do that for you.


Video Part I. Setting up and running on your local box to use SSL. Prerequisite: Follow ALL OF THE INSTRUCTIONS in the README of the git repo to clone a local copy and set up Redis.  


Video Part II. Registering your local copy of BBDN-LTI-Tool-Provider-Node (BLTPN) on the developer portal and using the values from the registration to configure your local BLTPN.


Video Part III. Registration of the 1.3 Tool in Learn, creating a deep-linking managed placement, using the link to create content with the BLTPN tool. Near the end of the video we look at how to use LTI 1.3 Names and Roles to get all of the users in the course the link was launched from.


Video Part IV. Demonstration of custom parameters from the Deep Link launch request and also a review of Names and Roles in that request.


The purpose of Names and Roles is to let the Tool Provider get all of the memberships in the course, and the role of each member with a call to one endpoint using LTI 1.3 security. Here's a screenshot of how this looks from the BLTPN - showing the first two members and their roles that were retrieved from the course.



We've had reports of REST API calls not working where the sole issue was the System Role Privileges not being set as required. I discovered this because I was trying to duplicate the issue and made this exact mistake - clicking the Ok button at the bottom of the page instead of using the Restrict or  Permit Privileges menu on the page.


Here's the When Ok is NOT OK Video Explanation.



Posted by mkauffman Jun 18, 2019

If you're running into an issue connecting to an AMI instance or a Developer Virtual machine where you get nowhere, or get a response like 'This site can't be reached. The connection was reset.' Use HTTPS!!


https://<my learn site><:port # if any>/


If it's a DVM or an AMI instance that's not had a valid SSL cert installed, you'll have to tell your browser to accept the cert.

I'm writing this blog to help you if you're having difficulty placing content in a course using REST APIs. For this example we'll use an LTI "managed placement" in an Original course. We'll show how to set the managed placement for a Course content tool that has an icon associated with it. One that looks like this Administrator Panel -> LTI Tool Providers -> Manage Placements: -> Edit placement page. (All credit to for the Map tool used in this example.)



1. The first step is to determine the JSON you need for the REST call to create the content. The easy way to do that is to use the Learn UI to go into a course as an instructor and use the UI to place the LTI managed placement link. We did that in a course without much else in it. Course -> Content -> Build Content -> A Tsugi Store Map


2. Now you want to see what the JSON should look like for the REST API call you will make that adds another "A Tsugi Store Map" link to the course. You need the course ID which is shown in the above screenshot as _1465_1. As the instructor, or admin, you can place the following in a web-browsers address field see how that JSON will look.


You will, of course, modify the URL for the Learn system and course you are working with:



The output includes the following JSON. You are looking for a stanza that starts with ,{"id":  and ends with },

,{"id":"_15790_1","parentId":"_15789_1","title":"A Tsugi Store Map","body":"<p>Course Content tool link placed in this Original course by the Instructor Using the UI.</p>","created":"2019-06-03T22:38:57.503Z","modified":"2019-06-03T22:38:57.511Z","position":0,"availability":{"available":"Yes","allowGuests":true,"adaptiveRelease":{}},"contentHandler":{"id":"resource/x-bb-bltiplacement-atsugistoremap","placementHandle":"atsugistoremap"}},


3. Now you can build JSON for the content you want to place. The JSON you create should look like the JSON for the content you discovered, less the id and created fields. For example:

{"title":"Yet Another Tsugi Store Map","body":"<p>Course Content tool link placed in this Original course by a REST API Call.</p>","availability":{"available":"Yes","allowGuests":true,"adaptiveRelease":{}},"contentHandler":{"id":"resource/x-bb-bltiplacement-atsugistoremap","placementHandle":"atsugistoremap"}}


4. Now you can add that to the course. First you get your access token. Then, as an example, use that to make the following call:

ganymede:~ mbk$ curl -k -X POST -H "Authorization: Bearer ZAEwWWGKqbMi3d2lBJOsaFXHbPLn60OF" -H "Content-Type: application/json" --data '{"title":"Yet Another Tsugi Store Map","body":"<p>Course Content tool link placed in this Original course by a REST  API Call.</p>","availability":{"available":"Yes","allowGuests":true,"adaptiveRelease":{}},"contentHandler":{"id":"resource/x-bb-bltiplacement-atsugistoremap","placementHandle":"atsugistoremap"}}'


You should see something like the following as a response:

{"id":"_17041_1","parentId":"_15789_1","title":"Yet Another Tsugi Store Map","body":"<p>Course Content tool link placed in this Original course by a REST API Call.</p>","created":"2019-06-13T00:11:18.660Z","modified":"2019-06-13T00:11:18.675Z","position":2,"availability":{"available":"Yes","allowGuests":true,"adaptiveRelease":{}},"contentHandler":{"id":"resource/x-bb-bltiplacement-atsugistoremap","placementHandle":"atsugistoremap"}}


And... Success! You have your new content in the course:

In conclusion you can use a similar to understand how to use REST to set any of the LTI managed placement  types as content, or any other content type supported by the REST API POST /learn/api/public/v1/courses/{courseId}/contents/{contentId}/children 



Remember to check the model!

If you're getting a 400 response from a REST API call to add a string to Ultra content with the message: "Could not read document: Invalid Blackboard Markup found in..." it's because Ultra restricts input to only valid BbML, a small subset of HTML.  While  your input worked for a Classic course, it does not work for an Ultra course.  For example, the style attribute of the p element is not considered valid BbML. 


So if you were to attempt POST to courses/(courseId)/gradebook/columns for an Ultra course,  and have the following HTML in the description field of the JSON:

{ "name": "A Grade Column Name", "description": "<p style=\"display: none;\">[]</p>",...


you get the 400 response and message.


See: for more details. 


Use only valid BbML.

Quite the problem is  mis-matched time on the Learn server and the tool provider. So first, make certain both servers are running some means of syncing to a time server, ex: ntpd. Second, from a case that I needed help from our OAuth expert with, make certain that the code that calculates the OAuth signature includes everything, including the port. Example: If the Learn server is available on then the OAuth signature calculation for the LTI launch must include the 8443 portion of the URL. 


May all your LTI launches be successful!