[Troubleshooting] Cannot find source of TypeError problem

1541732998
Hopefully someone can help me work this out without having to dive into all the code... I have a script that seems to be dying intermittently with the following error in the sandbox: TypeError: Cannot read property 'get' of undefined The working phrase is intermittently . Sometimes the script works, but sometimes it doesn't. And in every case, I am passing valid data from everything I can determine (mostly through ubiquitous use of sendChat). The character ID - which I can only assume is the culprit - comes from data held in state and works just fine in the other functions that pull character IDs from state. Is there a specific function that would through this error? And is there a reason why it would work only some of the time when given the exact same data?
1541733656
G G
Pro
Sheet Author
If it works intermittently, it's most likely something in your data isnt valid, sometimes. One of your objects (a character object, maybe) isnt being set probably. It's impossible for us to diagnose it without seeing relevant code though. You could look for any 'get' statements in your code, and wrap them in a try / catch block , and get it to log data when an error is caught.
1541735741
G G said: If it works intermittently, it's most likely something in your data isnt valid, sometimes. One of your objects (a character object, maybe) isnt being set probably. It's impossible for us to diagnose it without seeing relevant code though. You could look for any 'get' statements in your code, and wrap them in a try / catch block , and get it to log data when an error is caught. I can't see the possibility of anything not being set one moment and not set the next. It will literally fail right after working perfectly. And this is in a test game with no one else logged in and nothing else being done in-game except for my testing. The only get statements are in other sections of code. If you're willing to take a look I can point you to the github for it.
1541739757

Edited 1541739893
G G
Pro
Sheet Author
I dont think i have time for intensive error checking but I can skim it to see if anything jumps out at me. Linking the code will help others who view the thread. Ben L. said: I can't see the possibility of anything not being set one moment and not set the next. It will literally fail right after working perfectly.  That said, the. the error you showed above is telling you that you  definitely  have an undefined object or variable (most likely an object), so it's guaranteed that something isn't being set properly at some point in the code. There's no other way to get that error AFAIK. Having intermittent errors is pretty common, especially with code that contains multiple branches, loops, functions calling other functions, etc.  Also could you list the full error text, not just the one line above?
1541741922
G G said: I don't think i have time for intensive error checking but I can skim it to see if anything jumps out at me. Linking the code will help others who view the thread. Ben L. said: I can't see the possibility of anything not being set one moment and not set the next. It will literally fail right after working perfectly.  That said, the. the error you showed above is telling you that you  definitely  have an undefined object or variable (most likely an object), so it's guaranteed that something isn't being set properly at some point in the code. There's no other way to get that error AFAIK. Having intermittent errors is pretty common, especially with code that contains multiple branches, loops, functions calling other functions, etc.  Also could you list the full error text, not just the one line above? Just to be clear, the data I'm passing in for testing is exactly the same every time. Nothing changes on input. Here is the offending branch of code: https://github.com/blawson69/PurseStrings/tree/2.2?files=1
1541797050
put in log(token) and log(character) after you set those two items up but before you do your first ".get".  One of those two is most likely undefined and the calls out to the campaign object to set them up are incorrect somehow.  
1541818098
The Aaron
Pro
API Scripter
Do you get a call stack with that error?
1541869236
The Aaron said: Do you get a call stack with that error? I wish I knew what that meant.
1541872118
The Aaron
Pro
API Scripter
Often you will see an error, then a big concatenation of a bunch of code garbage. That code garbage is a list of the functions that were called to arrive at that error, kind of a “D was called by C, called by B, called by A.”
1541873074
So here's a little illustration of what's going on without looking at all  of the code. First of all, here is are my two functions and the sendChat lines I've been using to locate the issue: commandDist = function (msg) { // partyMembers array of character IDs initialized from state storage _.each(partyMembers, function (id) { var member = getObj('character', id); if (member) { sendChat('PurseStrings', '/w GM changePurse("' + splits.join(':') + '", "' + id + '", "add")', null, {noarchive:true}); var changed = changePurse(splits.join(':'), id, 'add'); sendChat('PurseStrings', '/w GM We maded it past changePurse()!', null, {noarchive:true}); } }); }, changePurse = function (pockets, char_id, type='add') { sendChat('PurseStrings', '/w GM Inside changePurse("' + pockets + '", "' + char_id + '", "' + type + '")', null, {noarchive:true}); // A lot of stuff happens here... var result = true; sendChat('PurseStrings', 'changePurse has ended! Result=' + result + ' and char_id = "' + char_id + '"', null, {noarchive:true}); return result; }, Here is a screenshot taken after one successful call to my script using "!ps --dist 35cp 62sp 388gp" and one unsuccessful call using the same command. The commandDist function uses character IDs stored in state to distribute loot. You'll see all of the above sendChat calls in order as expected, and the expected output in the Loot Distributed box. However, the last one that fails is still sending valid info to the changePurse function but we never get inside that function! You'll also notice that I am successfully calling getObj before we even get to that point. Yes, those sendChat lines are exactly where they are in the code. No extra lines have been removed for space in those places. So, How is it that it can work just fine one moment and break the next? I can repeat my "!ps --dist 35cp 62sp 388gp" call 4-5 times without it breaking. The character represented by "-LEaJelyDOsRnY_dInoW" is simply the first in the list. I have reset the list with another character first and this has not changed the behavior of the script. So, can you see why I am dumbfounded? There is no discernible reason why the code should be breaking. Can there be an issue with the sandbox itself having a hiccup of some sort? I just cannot for the life of me understand how this is happening.
1541873113
The Aaron said: Often you will see an error, then a big concatenation of a bunch of code garbage. That code garbage is a list of the functions that were called to arrive at that error, kind of a “D was called by C, called by B, called by A.” Just for you: TypeError: Cannot read property 'get' of undefined at changePurse (apiscript.js:9343:49) at commandDist (apiscript.js:9000:35) at handleInput (apiscript.js:8697:8) at eval (eval at <anonymous> (/home/node/d20-api-server/api.js:151:1), <anonymous>:65:16) at Object.publish (eval at <anonymous> (/home/node/d20-api-server/api.js:151:1), <anonymous>:70:8) at /home/node/d20-api-server/api.js:1634:12 at /home/node/d20-api-server/node_modules/firebase/lib/firebase-node.js:93:560 at hc (/home/node/d20-api-server/node_modules/firebase/lib/firebase-node.js:39:147) at Kd (/home/node/d20-api-server/node_modules/firebase/lib/firebase-node.js:93:546) at Id.Mb (/home/node/d20-api-server/node_modules/firebase/lib/firebase-node.js:93:489) at Zd.Ld.Mb (/home/node/d20-api-server/node_modules/firebase/lib/firebase-node.js:94:425) at /home/node/d20-api-server/node_modules/firebase/lib/firebase-node.js:111:400
1541875984
The Aaron
Pro
API Scripter
You get member, but never use it? where is splits defined?
1541878822
G G
Pro
Sheet Author
Ben posted the full code earlier, it's between lines 308-323 here https://github.com/blawson69/PurseStrings/blob/2.2/PurseStrings.js
1541923783

Edited 1541923834
The Aaron said: You get member, but never use it? where is splits defined? I removed the irrelevant code for clarity. I use member right after I set the changed variable with the changePurse function to add the member's name to a list: if (changed) { recipients.push(member.get('name')); } The splits variable is defined above the _.each loop when I calculate the amount of loot for each member: splits = _.values(tmpcoins); You can see the result of the join in that first line in the screenshot.
1541954706
Ammo
Pro
Hi Ben. If you make sure the script you are testing is the first script listed in your API sandbox, then the line numbers from your stack trace will actually be accurate.  As Scott recently taught me :) all API scripts are concatenated in the sandbox, so you get line numbers that are nonsense, unless you implement special handling of line numbers.   That's probably more than you want to deal with right now, but just putting your script first or making it the only script during testing (disable all other scripts temporarily) will allow you to get the exact location of the error in the stack trace.   Then you don't have to 'caveman debug' by putting logs everywhere. Cheers, Ammo For examples of translating error line numbers, you can see  https://github.com/derammo/der20/blob/7d6efd10dd813e6d49433a5ed4f563f16257d00a/include/header.js.txt#L2   or Scott's original: https://github.com/Roll20-Pathfinder-Character-Sheet/Companion-Script/blob/c7aa7a33ca8505972727546c885ecf798b98bb57/V1.01511665715/PFCompanion.js#L1   Ben L. said: The Aaron said: Often you will see an error, then a big concatenation of a bunch of code garbage. That code garbage is a list of the functions that were called to arrive at that error, kind of a “D was called by C, called by B, called by A.” Just for you: TypeError: Cannot read property 'get' of undefined at changePurse (apiscript.js:9343:49) at commandDist (apiscript.js:9000:35) at handleInput (apiscript.js:8697:8) at eval (eval at <anonymous> (/home/node/d20-api-server/api.js:151:1), <anonymous>:65:16) at Object.publish (eval at <anonymous> (/home/node/d20-api-server/api.js:151:1), <anonymous>:70:8) at /home/node/d20-api-server/api.js:1634:12 at /home/node/d20-api-server/node_modules/firebase/lib/firebase-node.js:93:560 at hc (/home/node/d20-api-server/node_modules/firebase/lib/firebase-node.js:39:147) at Kd (/home/node/d20-api-server/node_modules/firebase/lib/firebase-node.js:93:546) at Id.Mb (/home/node/d20-api-server/node_modules/firebase/lib/firebase-node.js:93:489) at Zd.Ld.Mb (/home/node/d20-api-server/node_modules/firebase/lib/firebase-node.js:94:425) at /home/node/d20-api-server/node_modules/firebase/lib/firebase-node.js:111:400
1541955126

Edited 1541955252
Ammo
Pro
About your error: the way changePurse would throw that error would be if you had selected a non-character token (like a lamp or someone's extra weapon or effect token.)  I believe in this case, char_id, which is token.get('represents') is blank, which results in 'character' not being found and so you are dereferencing undefined when you try to print the message about character.get('name') being not set up.    In general, every time you use findObjs or getObj, you must verify that you actually found something. I can't say this is definitely the problem, but that is the only use of get() that I could find in that function which is not guarded against character being not found. Cheers, Ammo
1541960962
Ammo said: About your error: the way changePurse would throw that error would be if you had selected a non-character token (like a lamp or someone's extra weapon or effect token.)  I believe in this case, char_id, which is token.get('represents') is blank, which results in 'character' not being found and so you are dereferencing undefined when you try to print the message about character.get('name') being not set up.    In general, every time you use findObjs or getObj, you must verify that you actually found something. I can't say this is definitely the problem, but that is the only use of get() that I could find in that function which is not guarded against character being not found. Cheers, Ammo Wherever I use selected tokens I am definitely checking to make sure it represents a character. In the case of my changePurse function, it is operating on an array of character IDs that have already been error checked before being added to the array. Thanks though! I will, however, be using your suggestion about being the only script in the sandbox! :)
1541994893

Edited 1541995451
Log, log, log.  Add TONS of logs everywhere, everywhere before you have a .get().  Label your logs with log("Get1" + Whatever)  log("Get2" + Whatever) until you find where you get an undefined.  Put a log in for every single get you have until you find where the thing you are trying to do a .get from is undefined.  Now that you've identified where the problem is, trace the code back.  Put more logs in, until you find out exactly what and where you are losing your object.  Eventually the why will become clear.  And then if the why isn't clear because of something funky working with Roll20, ask questions and you'll get an answer.  This is how I figured out Roll20AM (Roll20 Audio Master) and was able to take it over from Scott.  You need to learn the art of logging.  It will be your best friend other than google, in which we trust.  
1542080849
I followed the advice above about having my script as the only one and it worked! Of course. It is working just fine now. Thanks to everyone who gave a few moments of helpful advice!