Roll20 uses cookies to improve your experience on our site. Cookies enable you to enjoy certain features, social sharing functionality, and tailor message and display ads to your interests on our site and others. They also help us understand how our site is being used. By continuing to use our site, you consent to our use of cookies. Update your cookie preferences .
×
Create a free account

Some Warlock spells crashing API

One of the Warlocks in my game has recently leveled and now has 4th level spell slots, for some reason now when he tries to cast a 3rd level spell it crashes the API, Casting first, second or forth level spells is fine, it is just the 3rd level ones.  This is the error I get: Your scripts are currently disabled due to an error that was detected. Please make appropriate changes to your script's code and click the "Save Script" button. We will then attempt to start running the scripts again. More info... If this script was installed from the Script Library, you might find help in the Community API Forum. For reference, the error message generated was: Error: Firebase.update failed: First argument contains NaN in property 'current' Error: Firebase.update failed: First argument contains NaN in property 'current' at Ba (/home/node/d20-api-server/node_modules/firebase/lib/firebase-node.js:9:186) at Ba (/home/node/d20-api-server/node_modules/firebase/lib/firebase-node.js:10:207) at Aa (/home/node/d20-api-server/node_modules/firebase/lib/firebase-node.js:8:462) at Ea (/home/node/d20-api-server/node_modules/firebase/lib/firebase-node.js:10:403) at J.update (/home/node/d20-api-server/node_modules/firebase/lib/firebase-node.js:146:318) at TrackedObj._doSave (/home/node/d20-api-server/api.js:905:27) at Timeout.later [as _onTimeout] (/home/node/d20-api-server/node_modules/underscore/underscore-umd.js:1153:39) at listOnTimeout (internal/timers.js:549:17) at processTimers (internal/timers.js:492:7) I've seen similar error messages in posts but nothing that really gave me an answer on how to resolve it. The APIs I have installed are: 5th Edition OGL by Roll20 Companion G 5E Resting in Style G AddCustomTurn G WildHelpers G D&D 5E - WildShape G UDLWindows G APIHeartBeat G Aura/Tint HealthColors New Script He can cast a level 2 spell at level 2 and everything is fine, they can up cast the same spell at elvel 4 and everything is fine, but if they cast any spell, normal or upcast at level 3 the aPI crashes with that error message.
1639485404

Edited 1639485440
Oosh
Sheet Author
API Scripter
Are you able to disable the Companion script and see if you still get a crash? It seems the most likely culprit. Do other characters cause a crash when casting level 3 spells? Does the crash come after the spell is output to chat, but before Companion API spits out a "xxx Spell Slots remaining" message? Also, maybe check a few attributes on the problem character. If you select the token and post this to chat, what is the result? 2: @{selected|lvl2_slots_expended}/@{selected|lvl2_slots_total} 3: @{selected|lvl3_slots_expended}/@{selected|lvl3_slots_total} 4: @{selected|lvl4_slots_expended}/@{selected|lvl4_slots_total} Anything unusual show up?
Disabling the Companion Script, I can cast the spell and the API doesn't crash, it is definately something to do with the Companion script and spell slots. Other characters can cast 3rd level spells without crashing the APIs, even when they have no 3rd level spell slots left, it just comes up saying no slots left. I think it crashes the moment the spell is clicked, I can't say for certain, but the spell is cast but it doesn't come up to say hat there or no slots left for the Warlock as it does when I try and cast a 1st or 2nd level spell.  Trying that script out gave this result and didn't crash the API Oenanthe (GM): 2: 0/0 3: 0/0 4: 1/2 Being a Warlock as long as he can upcast the spell to level 4 it is fine, it is only when he has a 3rd level spell that can't be upcast is there a problem.  We can work around it, adn I can just restart the API sandbox after he has cast the problem spell, but it would be nice to get a solution (and may help others if they have the same problem).
1639548400
Oosh
Sheet Author
API Scripter
Hmmmm, well I can't reproduce the problem with a level 7 warlock. Does the crash still happen if you drag a completely new spell onto the character sheet from the Compendium? If you drag a problem spell onto a character with no spell slots (say, a barbarian or whatever), does it still crash? I figured it was something to do with Companion setting the spell slots remaining, since that's the only .set() operation I can think of when you cast a spell. My first thought was that charactermancer had left a bogus value in lvl3_slots_total when the lock leveled up and lost the slots, but from the chat info you posted it looks like the character has valid values in all the fields... I'll have another look through the Companion API when I get a chance, it must be pulling another number in from somewhere.
1639583172

Edited 1639583243
Andreas J.
Forum Champion
Sheet Author
Translator
Considering warlock's spellcasting and slot-tracking isn't quite same as all the other classes, and warlock's have had share of own bugs, I highly suspect this is tied to your character being a warlock. Roll20 last updated the Companion API exactly one year ago , so there is liekly room for improvement on the API script based on one year of sheet updates alone. Being a Warlock as long as he can upcast the spell to level 4 it is fine, it is only when he has a 3rd level spell that can't be upcast is there a problem. This is interesting, and sound like warlock upcasting spells that normally can't be upcast might be breaking the companion API. This is the parts of the API that handles spellslots (cut out non-spell stuff): on ( 'chat:message' , function ( msg ) { // ROLL LISTENERS else if ( msg . playerid . toLowerCase () != "api" && msg . rolltemplate ) { var cnamebase = msg . content . split ( "charname=" )[ 1 ]; var cname = cnamebase ? cnamebase . replace ( '}}' , '' ). trim () : ( msg . content . split ( "{{name=" )[ 1 ]|| '' ). split ( "}}" )[ 0 ]. trim (); var player = getObj ( "player" , msg . playerid ); var character = undefined ; if ( cname ) { list = findObjs ({ name : cname , type : 'character' },{ caseInsensitive : true }); if ( list != undefined ){ if ( list . length > 1 ){ log ( 'Duplicate character names, process cancelled' ); return ; } } character = list [ 0 ] } if ([ "spell" ]. indexOf ( msg . rolltemplate ) > - 1 ) { if ( msg . content . indexOf ( "{{level=" ) > - 1 && character && state . FifthEditionOGLbyRoll20 . spelltracking != "off" ) { handleslotspell ( msg , character , player ); } } } }); var handleslotspell = function ( msg , character , player ) { var spellslot = (( msg . content . split ( "{{level=" )[ 1 ]|| '' ). split ( "}}" )[ 0 ]|| '' ). split ( " " )[ 1 ]; var ritual = msg . content . indexOf ( "{{ritual=1}}" ) > - 1 ? true : false ; var innate = msg . content . indexOf ( "{{innate=}}" ) > - 1 ? false : true ; if ( spellslot === "0" || spellslot === "cantrip" || spellslot === "npc" || ritual || innate ) { return ; } resolveslot ( msg , character , player , spellslot ); }; var resolveslot = function ( msg , character , player , spellslot ) { var charslot = findObjs ({ type : 'attribute' , characterid : character . id , name : "lvl" + spellslot + "_slots_expended" }, { caseInsensitive : true })[ 0 ]; if (! charslot ) { charslot = createObj ( "attribute" , { name : "lvl" + spellslot + "_slots_expended" , current : "0" , max : "" , characterid : character . id }); //var charslot = findObjs({type: 'attribute', characterid: character.id, name: "lvl" + spellslot + "_slots_expended"}, {caseInsensitive: true})[0]; } var charslotmax = findObjs ({ type : 'attribute' , characterid : character . id , name : "lvl" + spellslot + "_slots_total" }, { caseInsensitive : true })[ 0 ]; if (! charslotmax ) { charslotmax = createObj ( "attribute" , { name : "lvl" + spellslot + "_slots_total" , current : "0" , max : "" , characterid : character . id }); //var charslotmax = findObjs({type: 'attribute', characterid: character.id, name: "lvl" + spellslot + "_slots_total"}, {caseInsensitive: true})[0]; } var spent = parseInt ( charslot . get ( "current" ), 10 ); charslot . set ({ current : Math . max ( spent - 1 , 0 )}); var wtype = getAttrByName ( character . id , "wtype" ); var wtoggle = getAttrByName ( character . id , "whispertoggle" ); let displayName = player . get ( 'displayname' ); let playerName = "" ; if ( state . FifthEditionOGLbyRoll20 . spelltracking === "player" ) playerName = ( displayName === undefined || playerIsGM ( player . get ( "_id" ))) ? undefined : `/w " ${ player . get ( 'displayname' ) } " ` ; var sendPlayerMsg =( playerName !== "" || wtype === "" || ( wtype === "@{whispertoggle}" && wtoggle === "" ) || ( wtype === "?{Whisper?|Public Roll,|Whisper Roll,/w gm }" && msg . type === "general" )); var sendGMMsg =( playerName !== "" || wtype === "/w gm " || ( wtype === "@{whispertoggle}" && wtoggle === "/w gm " ) || ( wtype === "?{Whisper?|Public Roll,|Whisper Roll,/w gm }" && msg . type === "whisper" )); if ( spent > 0 ) { if ( state . FifthEditionOGLbyRoll20 . spelltracking != "quiet" ) { if ( sendPlayerMsg ) { if ( playerName !== undefined ) sendChat ( msg . who , playerName + "<div class='sheet-rolltemplate-simple' style='margin-top:-7px;'><div class='sheet-container'><div class='sheet-label' style='margin-top:5px;'><span style='display:block;'>SPELL SLOT LEVEL " + spellslot + "</span><span style='display:block;'>" + Math . max ( spent - 1 , 0 ) + " OF " + charslotmax . get ( "current" ) + " REMAINING</span></div></div></div>" ); } if ( sendGMMsg ) { sendChat ( msg . who , "/w gm <div class='sheet-rolltemplate-simple'><div class='sheet-container'><div class='sheet-label' style='margin-top:5px;'><span style='display:block;'>SPELL SLOT LEVEL " + spellslot + "</span><span style='display:block;'>" + Math . max ( spent - 1 , 0 ) + " OF " + charslotmax . get ( "current" ) + " REMAINING</span></div></div></div>" ); } } } else { if ( sendPlayerMsg ) { if ( playerName !== undefined ) sendChat ( msg . who , playerName + "<div class='sheet-rolltemplate-simple' style='margin-top:-7px;'><div class='sheet-container'><div class='sheet-label' style='margin-top:5px;'><span style='display:block;'>SPELL SLOT LEVEL " + spellslot + "</span><span style='display:block; color:red;'>ALL SLOTS EXPENDED</span></div></div></div>" ); } if ( sendGMMsg ) { sendChat ( msg . who , "/w gm <div class='sheet-rolltemplate-simple'><div class='sheet-container'><div class='sheet-label' style='margin-top:5px;'><span style='display:block;'>SPELL SLOT LEVEL " + spellslot + "</span><span style='display:block; color:red;'>ALL SLOTS EXPENDED</span></div></div></div>" ); } } };
I've managed to get some testing in today, and gave the Barbarian some spells for a short length of time and he had no problem with casting them, so it is definately something in the Warlock not the spells or the Companion script.  Next test it to creat another Warlock and level them to 7 and see if it happens on a new character or if there may be a bug on just that one.
Having managed to get some time to do some testing, I may have got an reason if not an answer to the problem, so i'll mention what I I have found out. The Warlock in question is still crashing the API when i try and cast any spell at 3rd level. I tried adding spells to the party's barbarian and could cast them even though they had no spell slots with out issue. I created another Warlock and leveled it up and it could cast the spells no problem.  So it seems the problem is just on that one character sheet, either something went wrong when the character was created, a bug has crept in when it was leveled up, or is tis just one of those wierd things that computers throw up from time to time. I then decided to recreate the character for the player in hope of resolving the problem that way.  That is when I realised the character must have been created manually not through the charactermancer, it was for a patron I don't have in my Compendium and many sections were obviously entered manually.  While not certain, i'm wondering if that is where the problem originates. No real answer here, but if anyone suffers a similar problem at least it might give them something to look at and eliminate first.
1639977415
Oosh
Sheet Author
API Scripter
It's certainly odd - the only attribute that seems to be used in the .set() operation is lvlX_slots_expended, but it looked like it had an OK value from what you posted before. Depending on how much trouble you want to go to, we could add some error handling to the spell slot tracking to make sure that's where the crash is coming from. It would mean disabling the one-click and manually installing, is all. If you've already recreated the character it might not be worth the bother.
Thank you for the offer, but having recreated the character I think i will see how it goes, if the problem reappears when he has leveled up a couple of times and gained a new level of spell slot then it may be worth digging deeper.  My programming knowledge is non existant, I managed an HTML course, but having to do a seperate CSS file and link it just left me getting confused, copy/pasting API scripts from Github if they arent' in the drop down menu is about my limit.  I have a feeling that something in that character's sheet has been corrupted somehow, whether it is because the character was created manually or whether it is just one of those strange computer things, I have no idea, currently the new character is working and that is really all I ask. So thank you for the help you have given, even if some of it was pointing out some obvious things to try that i just hadnt' thought off.  One thing I have learnt with computers is that sometimes things get sorted with no real idea of why it went wrong and what you did to correct it.
1640018656
Andreas J.
Forum Champion
Sheet Author
Translator
I think i will see how it goes, if the problem reappears when he has leveled up a couple of times and gained a new level of spell slot then it may be worth digging deeper. Yeah, sounds smart as Oosh wasn't able to reproduce the error (and I didn't try).
1640054983
Oosh
Sheet Author
API Scripter
I sent you a PM with an invite link - if you get bored, throw a copy of the problem Warlock into that game and I'll poke it with a sharp stick when I get a minute.
1640131648

Edited 1640132005
Oosh
Sheet Author
API Scripter
Okay, I think I've found the issue. On the original character sheet, go to the expended slots for lvl3, remove whatever is in there and just put a plain old number. Maybe a "1". Now try casting a couple of lvl 3 spells in a row and see if it fixes it. Now try going to the level 2 slots remaining, and put "0 " including a space , and push enter. Try casting a level 2 spell and see if you get the crash. It seems that HTML's handling of number inputs is the problem. Whitespace is not allowed, which is fine, the problem is there's no indication that there's whitespace in the input area - as far as the user is concerned the value looks fine, but the HTML value becomes "". That makes the content of the input box visible to the user, but completely empty to any script looking at the DOM. This is awful design, and I'm not sure how it ended up this way (this is all HTML, not Roll20). So the cause isn't the fault of the Companion API scripts, though it could throw a isNaN() check in there to avoid the crash. This does make number inputs problematic for character sheets in general, as the HTML value cannot be read there's not much the firebase end can do about it. The best use case is to disable direct input & only use the spinner buttons, or just use a text field where whitespace doesn't break the value property. There is a site-wide solution (which I just tested very briefly) which is disabling spacebar at the <iframe> level when a number input is focused. This worked on the 5e sheet, anyway. This test worked for me on a single character sheet: const blockSpace = ( ev ) => {   if ( ev . target . type === 'number' && / ^ \s + $ / . test ( ev . key )) {     console . log ( 'Computer says no!' );     ev . preventDefault ();   } } document . querySelector ( 'iframe' ). contentDocument . addEventListener ( 'keydown' , blockSpace ); A proper solution would need to call this function whenever a character sheet is opened & fully loaded. That would prevent whitespace errors in any sheet/system, unless a user decides to paste a broken value from the clipboard. Long story short - I think your warlock bumped spacebar at some point when entering their spell slots. " 0" or "0 ". :)
1640182102
Andreas J.
Forum Champion
Sheet Author
Translator
Oosh said: There is a site-wide solution (which I just tested very briefly) which is disabling spacebar at the &lt;iframe&gt; level when a number input is focused. This worked on the 5e sheet, anyway. This test worked for me on a single character sheet: const blockSpace = ( ev ) =&gt; { &nbsp; if ( ev . target . type === 'number' &amp;&amp; / ^ \s + $ / . test ( ev . key )) { &nbsp; &nbsp; console . log ( 'Computer says no!' ); &nbsp; &nbsp; ev . preventDefault (); &nbsp; } } document . querySelector ( 'iframe' ). contentDocument . addEventListener ( 'keydown' , blockSpace ); So saving this as a tampermonkey script targeting <a href="https://app.roll20.net/editor/" rel="nofollow">https://app.roll20.net/editor/</a> would keep this fix active when in a roll20 game? It seems that HTML's handling of number inputs is the problem. Whitespace is not allowed, which is fine, the problem is there's no indication that there's whitespace in the input area - as far as the user is concerned the value looks fine, but the HTML value becomes "". Does this means it can't be solved from a sheet design perspective? Like creating a sheetworker to trim whitespaces from all number inputs? [...] as the HTML value cannot be read there's not much the firebase end can do about it Considering the stat are still stored in firebase, it sounds like sheetworkers could made to do it, but yeah ideally a universal fix would be implemented by Roll20. So the cause isn't the fault of the Companion API scripts, though it could throw a isNaN() check in there to avoid the crash. APIs like this could have extra error-handling to still work for the rare cases when inputs have managed to sneak in trailing whitespaces, and/or reply to user with error-msg about the stat.
Well having being trying what Oosh suggest regarding spaces in the number slots, it was sorting of working, sometimes it would work, sometimes it would crash.&nbsp; Once i had the 3rd level spells working I then couldn't get it to crash again, i managed to get it to do it once putting the space into the 2nd level ones, then i couldn't get it to do it again.&nbsp; I have a feeling that when I'm changing the number and adding the space it may not always be in the right place, or hitting the enter key after wards may make a difference. As for the rest of what has been said, that has gone right over my head, so I think I will leave this in far more capable hands than mine.&nbsp; In the end we seem to have found out where the bug was, but the one thing I do know about computers just finding the bug is just the start of sorting it out, and fising it can bring up another couple of dozen bugs all of their own.
1640185155
Andreas J.
Forum Champion
Sheet Author
Translator
As for the rest of what has been said, that has gone right over my head, Yeah sorry it was addressed to Oosh, and just saying out loud things that could help in creating a general solution to prevent this from popping up elsewhere, now that it seems (mostly) solved. Well having being trying what Oosh suggest regarding spaces in the number slots, it was sorting of working, sometimes it would work, sometimes it would crash. So it's still sometimes crashing, even though the attribute have been checked to have no extra spaces?
It wasn't just what you said that went over my head quite a bit of what Oosh was explaining did.&nbsp; I tried to take out the numbers for the spell slots and put them back in, sometimes including a space sometimes not, once whenI did it with a space inthe level 2 spell slot it crashed the API, and when I took it out of the 3rd level slot it didn't, but then try to repeat it didn't seem to work and the API was remaining stubbornly stable.
1640238548

Edited 1640239411
Oosh
Sheet Author
API Scripter
Oenanthe said: ... and the API was remaining stubbornly stable. That sounds like a good problem to have! :) Andreas J. said: So saving this as a tampermonkey script targeting <a href="https://app.roll20.net/editor/" rel="nofollow">https://app.roll20.net/editor/</a> would keep this fix active when in a roll20 game? Well, I'd consider removing the console.log line first... and also it needs an mutation observer or similar to detect an &lt;iframe&gt; opening and attach the event handler each time. Unless tampermonkey does that for you? I haven't used it. Basically each time a character sheet is opened it needs to grab the collection of $('iframe') and apply the handler to the last entry. Does this means it can't be solved from a sheet design perspective? Like creating a sheetworker to trim whitespaces from all number inputs? Considering the stat are still stored in firebase, it sounds like sheetworkers could made to do it, but yeah ideally a universal fix would be implemented by Roll20 Well that's the problem. As soon as the 'change' event is fired, if there was any whitespace in there the value is now an empty string. You can't fix it downstream from there, as you're just passing the empty string to a cleanup function . I have seen a suggestion on stackExchange of using the 'blur' event to get hold of the value before the 'change' event fires, didn't test it though. It seems unlikely to me that it would work. The 'input' event doesn't work either - the moment whitespace goes in there, the value is emptied. Example, pushing space after the third '1', then backspace, then space again. The other problem is that firebase is not storing the value. Example - stamina starts as a plain 0, then changes to a "0 ": Again we've got the problem where "@{alice|stamina}" in the chat bar returns a misleading 0 (I think that's just due setting the default value=0 in the sheet's html), while the actual data value is an empty string. Hence the API crash, it's receiving a "" from firebase, not the "0" default value from the HTML (which is obviously utterly useless to the API unless you want the value to always be 0).