JavaScripting Help - TypeError: Cannot Convert Null to an Object

- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
10-18-2022 12:26 PM - edited 10-18-2022 12:40 PM
Hey ServiceNow Community! Hoping to get some help on this in-depth JavaScript issue I'm having on this very large application we have. I will try to explain the process as best as I can.
So we ended up getting a request notifying us that part of our Server Decommission workflow was erroring out;
"Cannot convert null to an object" Line 35
So we have two different workflows for this Server Decommission, if they submit for strictly a Server Decommission, the script works perfectly fine, but if they submit for an Application Retirement, that then leads to a Server Decommission, we get this error above. Since this portion is erroring out, you will see we skip over 3 different possible workflows that are supposed to get triggered to decommission the server depending on it's type. Here is the script that is erroring out; (if the script doesn't error out it's supposed to be able to determine what type of server it is and go to that next workflow)
//Bring in list collector and create arrays for Windows Servers and Non-Windows Servers
var arrWinPhysSrvs = [];
var arrWinVirtSrvs = [];
var arrNonWinPhysSrvs = [];
var arrNonWinVirtSrvs = [];
//new:
var arrNHAZWinSrvs = [];
var arrNHAZLinuxSrvs = [];
//end new
var collector;
if (workflow.inputs.name_of_app) {
var appServers = workflow.scratchpad.appServers.toString();
collector = appServers;
workflow.info('App Server Decom ' + collector + ' RITM: ' + current.number);
} else {
var servers = current.getElement('variables.servers_selected_to_decommission').toString();
collector = servers;
workflow.info('Server Decom ' + collector + ' RITM: ' + current.number);
}
workflow.info('Application Services from scratchpad ' + collector + ' RITM: ' + current.number);
var arrayCi = collector.split(",");
arrayCi.forEach(function(server){
var class_to_match = "cmdb_ci_win_server";
var azure_name_to_match = 'nhaz';
var grCi = new GlideRecord("cmdb_ci_server");
grCi.get(server);
var server_class = grCi.getValue("sys_class_name");
var server_is_virtual = grCi.getValue("virtual");
var serverName = grCi.getValue('name').toLowerCase();
var server_is_azure = serverName.substring(0,4);
var server_sys_id = grCi.getUniqueValue();
var server_dv = grCi.getDisplayValue();
workflow.info(
'\nserver_class ' + server_class +
'\nserver_is_virtual ' + server_is_virtual +
'\nserver_dv ' + server_dv +
'\nserver_sys_id ' + server_dv
);
if ( server_class == class_to_match ) {
if (server_is_virtual == 1){
if (server_is_azure != azure_name_to_match){
arrWinVirtSrvs.push(server_sys_id);
workflow.info("CI: " + server_dv + " (" + server_sys_id +") pushed to arrWinVirtSrvs");
workflow.scratchpad.is_windows = true;
}
if (server_is_azure == azure_name_to_match){
arrNHAZWinSrvs.push(server_sys_id);
workflow.info("CI: " + server_dv + " (" + server_sys_id +") pushed to arrNHAZWinSrvs");
workflow.scratchpad.is_az_windows = true;
}
} else {
arrWinPhysSrvs.push(server_sys_id);
workflow.info("CI: " + server_dv + " (" + server_sys_id +") pushed to arrWinPhysSrvs");
workflow.scratchpad.is_windows = true;
}
} else {
if (server_is_virtual == 1) {
if (server_is_azure != azure_name_to_match){
arrNonWinVirtSrvs.push(server_sys_id);
workflow.info("CI: " + server_dv + " (" + server_sys_id +") pushed to arrNonWinVirtSrvs");
workflow.scratchpad.is_linux = true;
}
if (server_is_azure == azure_name_to_match){
arrNHAZLinuxSrvs.push(server_sys_id);
workflow.info("CI: " + server_dv + " (" + server_sys_id +") pushed to arrNHAZLinuxSrvs");
workflow.scratchpad.is_az_linux = true;
}
} else {
arrNonWinPhysSrvs.push(server_sys_id);
workflow.info("CI: " + server_dv + " (" + server_sys_id +") pushed to arrNonWinPhysSrvs");
workflow.scratchpad.is_linux = true;
}
}
});
current.variables.win_physical_servers_to_decommission = arrWinPhysSrvs.join();
current.variables.win_virtual_servers_to_decommission = arrWinVirtSrvs.join();
current.variables.nonwin_physical_servers_to_decommission = arrNonWinPhysSrvs.join();
current.variables.nonwin_virtual_servers_to_decommission = arrNonWinVirtSrvs.join();
current.variables.win_az_virtual_servers_to_decommission = arrNHAZWinSrvs.join();
current.variables.non_win_az_virtual_servers_to_decommission = arrNHAZLinuxSrvs.join();
workflow.info("current.variables.win_physical_servers_to_decommission = " + current.variables.win_physical_servers_to_decommission);
workflow.info("current.variables.win_virtual_servers_to_decommission = " + current.variables.win_virtual_servers_to_decommission);
workflow.info("current.variables.nonwin_physical_servers_to_decommission = " + current.variables.nonwin_physical_servers_to_decommission);
workflow.info("current.variables.nonwin_virtual_servers_to_decommission = " + current.variables.nonwin_virtual_servers_to_decommission);
workflow.info("current.variables.win_az_virtual_servers_to_decommission = " + current.variables.win_az_virtual_servers_to_decommission);
workflow.info("current.variables.non_win_az_virtual_servers_to_decommission = " + current.variables.non_win_az_virtual_servers_to_decommission);
You'll notice on Line 12 is when we determine if Application Retirement was running previously or if we can skip that and go straight to the else statement. So the ELSE statement works fine, when Server Decommission has been ran ONLY. However if Application Retirement runs first and we call for Server Decommission workflow from it, it runs through the IF statement and gives us that error.
So the portion in question that is NULL is the following;
Line 29 var grCi = new GlideRecord("cmdb_ci_server");
Line 30 grCi.get(server);
Line 34 var serverName = grCi.getValue('name').toLowerCase();
Line 35 var server_is_azure = serverName.substring(0,4);
Just before that script that is erroring, we have this script running to try and grab specific variables from the RITM that was running the Application Retirement workflow;
//gets servers from parent flow for Application Rationalization.
if (workflow.inputs.name_of_app){
workflow.info('Workflow call from AppRat cat item. Name of app: ' + workflow.inputs.name_of_app + ' RITM: ' + current.number);
var arr = [];
var appname = new NovantUtils();
var servers_selected_to_decommission = current.variables.servers_selected_to_decommission;
arr = appname.getServersDownstream(workflow.inputs.name_of_app);
workflow.scratchpad.appServers = arr + "";
//workflow.info('Decommission servers: ' + arr + ' RITM: ' + current.number);
workflow.info('Servers to Decommission are: ' + workflow.scratchpad.appServers + ' RITM: ' + current.number);
} else {
workflow.info("Not called from AppRat cat item, assuming Server Decom cat item.");
}
And here is the code that goes to NovantUtils under the function getServerDownstream;
getServersDownstream: function(parent) {
var types = 'type=1a9cb166f1571100a92eb60da2bce5c5^ORtype=60bc4e22c0a8010e01f074cbe6bd73c3^ORtype=616a137fdba473488cc512484b961947';
//Query the environment m2m, push the Environments to the array
var enviArray = [];
enviArray.push(parent);
var env = new GlideRecord("cmdb_environment_to_ci");
env.addEncodedQuery("ci=" + parent);
env.query();
while (env.next()) {
enviArray.push(env.environment.getValue('sys_id'));
}
enviArray = enviArray.join(',');
var childrenArray = [];
var childServer = new GlideRecord("cmdb_rel_ci");
childServer.addEncodedQuery("parent.sys_idIN" + enviArray); //Look for all items tied to either the Business App or it's associated Environments
childServer.addEncodedQuery('child.sys_class_nameINSTANCEOFcmdb_ci_server'); //Only grab items that are Servers
childServer.addEncodedQuery(types); //Only query for the following relationship types: Environs::Environed by, Runs on::Runs, Depends on::Used by
childServer.query();
while (childServer.next()) {
childrenArray.push(childServer.child.getValue('sys_id'));
}
childrenArray = childrenArray.join(',');
return childrenArray;
},
During my research on this issue, it looks like on the getServersDownstream it's calling for a table cmdb_environment_to_ci. Looks like originally this is where they stored the server data possibly? However this table is now completely empty, it seems we are getting our data from cmdb_ci_servers table now.
So I changed the script to the following;
getServersDownstream: function(parent) {
var types = 'type=1a9cb166f1571100a92eb60da2bce5c5^ORtype=60bc4e22c0a8010e01f074cbe6bd73c3^ORtype=616a137fdba473488cc512484b961947';
//Query the environment m2m, push the Environments to the array
var enviArray = [];
enviArray.push(parent);
var env = new GlideRecord("cmdb_ci_server");
env.addEncodedQuery("name=" + parent);
env.query();
while (env.next()) {
enviArray.push(env.environment.getValue('sys_id'));
}
enviArray = enviArray.join(',');
var childrenArray = [];
var childServer = new GlideRecord("cmdb_rel_ci");
childServer.addEncodedQuery("parent.sys_idIN" + enviArray); //Look for all items tied to either the Business App or it's associated Environments
childServer.addEncodedQuery('child.sys_class_nameINSTANCEOFcmdb_ci_server'); //Only grab items that are Servers
childServer.addEncodedQuery(types); //Only query for the following relationship types: Environs::Environed by, Runs on::Runs, Depends on::Used by
childServer.query();
while (childServer.next()) {
childrenArray.push(childServer.child.getValue('sys_id'));
}
childrenArray = childrenArray.join(',');
return childrenArray;
},
If I run this in a background script and feed in some data manually, I do get data;
From here I cannot figure out why for the life of me, this data isn't getting passed over to our Server Decommission workflow when the Application Retirement workflow calls for it to run. That IF statement seems to just not be pulling any data into the collector... Again if we skip the IF statement, and just the Server Decommission workflow runs stand alone, the script works perfectly fine and it grabs the list of servers from the RITM that need to be decommissioned.
Above is the field on our RITM Variables that lists out what servers to decommission.
Any ideas on this? Thank you for the help in advance. I will do my best to answer any questions. This application is pretty large and many hands have been on it before me. Also this is just a bit above my head in terms of troubleshooting JavaScript. I can get myself around JavaScript, but this is above me. Haha
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
10-18-2022 12:37 PM
Since it works fine when submitted as standalone server decom, the workflow and most of the logic in the script is probably fine.
I suspect it's something with the inputs, passing values from the Application Retirement to the Server Decom workflow.
Can you take a screenshot of how you are calling this workflow from the Application Retirement workflow and also a screenshot of the inputs?

- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
10-18-2022 12:51 PM
Sure thing, here is the Application Retirement workflow, I've underlined where the Server Decommission is getting called;
How would I obtain the inputs for you? I apologize never messed with inputs.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
10-18-2022 01:05 PM
Open up the the Application Retirement workflow in workflow editor. Then double click on the Server Decommission activity

- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
10-18-2022 01:06 PM
Gotcha! This is all that it shows;