Can anyone help me understand this error message?

Error running script: Error evaluating expression 'GetDirectChildren(game.pov.parent)': Collection was modified; enumeration operation may not execute.
Error running script: Error evaluating expression 'GetAllChildObjects(game.pov)': Collection was modified; enumeration operation may not execute.
Error running script: Error evaluating expression 'ListCombine(ScopeReachableNotHeldForRoom(room), ScopeReachableInventory())': Value cannot be null.Parameter name: collection
Error running script: Unrecognised list type
Error running script: Error evaluating expression 'ListCombine(ScopeReachableNotHeldForRoom(room), ScopeVisibleNotReachableForRoom(room))': Value cannot be null.Parameter name: collection
Error running script: Cannot foreach over '' as it is not a list
Error running script: Error evaluating expression 'ListExclude(ScopeVisibleNotHeldNotScenery(), game.pov)': Object reference not set to an instance of an object.


I am not an expert but I think it means the quest app is trying to execute what you want it to do as per your written code instructions, unfortunately the execution stops because the requirement is suddenly gone, most possibly an object since the very first error line states 'GetDirectChildren(game.pov.parent)'

My easier ways are to

  1. Make things invisible rather than moving objects away from the room, this means the object is still in the room and will possibly still trigger your written code
  2. Slow down the timer of moving objects in and out of the room, giving time for quest app to execute codes seems to help a lot, not just for this error, but for many other errors as well

Mrangel's difficult ways are

  1. Freeze internal functions, in quest app bottom left, there is a filter list to open all the internal functions, basically, you disable all the relevant internal function by using a simple if else loop, if you are moving objects, disable all internal functions, else, enable all internal functions
  2. Hiding all notification errors at UI Initialisation script:
JS.eval("$(function(){var t=addText;addText=function(n){n.match(/>Error running script:/)?console.log($(n).text()):t(n)}});")

To access UI Initialisation script, at game object, tickbox show advanced scripts for the game object, click advanced scripts tab, press code view, copy and paste JS.eval ("$(function(){var t=addText;addText=function(n){n.match(/>Error running script:/)?console.log($(n).text()):t(n)}});")

A common error is that game creators use GUI function to create javascript textbox and copy and paste code, this results in two javascript which basically disable the whole function

  1. Optimizing the game coding via dictionary, lets not go into this @.@
    But for anyone that is interested in this long and advanced method which will probably optimize all of your other games as well, you can learn from mrangel at
    https://textadventures.co.uk/forum/quest/topic/esxx6dguiuoaqrku5b6ihg/fishy-error

I have combined my fishing game with the same errors as yours with mrangel's 2. Hiding all notification errors at UI Initialisation script
You can try out the small demostration which works without errors at
https://textadventures.co.uk/games/view/57zl3sqjdeoeuqwqok9r5q/test

Or perhaps you are skeptical and think the original game is already without errors, then you can download the original game here

<!--Saved by Quest 5.8.6836.13983-->
<asl version="580">
  <include ref="English.aslx" />
  <include ref="Core.aslx" />
  <game name="test">
    <gameid>d1d77751-bc11-4993-9b37-cc7a5061a6f0</gameid>
    <version>1.0</version>
    <firstpublished>2024</firstpublished>
    <showmoney />
  </game>
  <object name="room">
    <inherit name="editor_room" />
    <isroom />
    <object name="player">
      <inherit name="editor_object" />
      <inherit name="editor_player" />
    </object>
    <object name="fish">
      <inherit name="editor_object" />
      <catch type="script">
        msg ("You caught a "+this.alias)
        msg ("$"+this.price+ " have been added.")
        add = ToInt(this.price)
        player.money = player.money + add
        this.parent = null
      </catch>
      <displayverbs type="stringlist" />
    </object>
  </object>
  <verb>
    <property>catch</property>
    <pattern>catch</pattern>
    <defaultexpression>"You can't catch " + object.article + "."</defaultexpression>
  </verb>
  <timer name="fish timer">
    <interval>1</interval>
    <script>
      for (repeat, 1, 40, 1) {
        rng = GetRandomInt(1,40)
        if (rng=1) {
          game.fishname = "monkfish"
          game.fishprice = "1"
        }
        if (rng=2) {
          game.fishname = "rainbow trout"
          game.fishprice = "2"
        }
        if (rng=3) {
          game.fishname = "electric eel"
          game.fishprice = "2"
        }
        if (rng=4) {
          game.fishname = "lionfish"
          game.fishprice = "5"
        }
        if (rng=5) {
          game.fishname = "flying fish"
          game.fishprice = "6"
        }
        if (rng=6) {
          game.fishname = "swordfish"
          game.fishprice = "20"
        }
        if (rng=7) {
          game.fishname = "mirror carp"
          game.fishprice = "50"
        }
        if (rng=8) {
          game.fishname = "slippery snook"
          game.fishprice = "0"
        }
        if (rng=9) {
          game.fishname = "jellyfish"
          game.fishprice = "2"
        }
        if (rng=10) {
          game.fishname = "gigagoldfish"
          game.fishprice = "40"
        }
        if (rng=11) {
          game.fishname = "mystery mackerel"
          game.fishprice = "1"
        }
        if (rng=12) {
          game.fishname = "time trout"
          game.fishprice = "2"
        }
        if (rng=13) {
          game.fishname = "flaming fin"
          game.fishprice = "4"
        }
        if (rng=14) {
          game.fishname = "piranha"
          game.fishprice = "5"
        }
        if (rng=15) {
          game.fishname = "bananafish"
          game.fishprice = "10"
        }
        if (rng=16) {
          game.fishname = "axolotl"
          game.fishprice = "22"
        }
        if (rng=17) {
          game.fishname = "betta fish"
          game.fishprice = "0"
        }
        if (rng=18) {
          game.fishname = "discus fish"
          game.fishprice = "8"
        }
        if (rng=19) {
          game.fishname = "sea dragon"
          game.fishprice = "30"
        }
        if (rng=20) {
          game.fishname = "moon jellyfish"
          game.fishprice = "40"
        }
        if (rng=21) {
          game.fishname = "koi"
          game.fishprice = "2"
        }
        if (rng=22) {
          game.fishname = "thunder crayfish"
          game.fishprice = "3"
        }
        if (rng=23) {
          game.fishname = "mandarin fish"
          game.fishprice = "1"
        }
        if (rng=24) {
          game.fishname = "dwarf pufferfish"
          game.fishprice = "1"
        }
        if (rng=25) {
          game.fishname = "peacock mantis shrimp"
          game.fishprice = "19"
        }
        if (rng=26) {
          game.fishname = "fire shrimp"
          game.fishprice = "1"
        }
        if (rng=27) {
          game.fishname = "fancy snail"
          game.fishprice = "0"
        }
        if (rng=28) {
          game.fishname = "african dwarf frog"
          game.fishprice = "2"
        }
        if (rng=29) {
          game.fishname = "angelfish"
          game.fishprice = "4"
        }
        if (rng=30) {
          game.fishname = "lobster"
          game.fishprice = "6"
        }
        if (rng=31) {
          game.fishname = "datastream darter"
          game.fishprice = "20"
        }
        if (rng=32) {
          game.fishname = "neon ripplefish"
          game.fishprice = "11"
        }
        if (rng=33) {
          game.fishname = "chromeback salmon"
          game.fishprice = "15"
        }
        if (rng=34) {
          game.fishname = "solar sailfish"
          game.fishprice = "16"
        }
        if (rng=35) {
          game.fishname = "hypercurrent eel"
          game.fishprice = "25"
        }
        if (rng=36) {
          game.fishname = "plasma pike"
          game.fishprice = "50"
        }
        if (rng=37) {
          game.fishname = "bio-luminescent leviathan"
          game.fishprice = "100"
        }
        if (rng=38) {
          game.fishname = "magnetic manta"
          game.fishprice = "40"
        }
        if (rng=39) {
          game.fishname = "hydrodynamic hologram"
          game.fishprice = "2"
        }
        if (rng=40) {
          game.fishname = "quantum quagga"
          game.fishprice = "60"
        }
        if (RandomChance(11)) {
          fish.alias = ""+game.fishname
          fish.price = ""+game.fishprice
          CloneObjectAndMoveHere (fish)
        }
        else {
          foreach (object, GetDirectChildren (game.pov.parent)) {
            if (object.alias = ""+game.fishname) {
              object.parent = null
            }
          }
        }
      }
    </script>
    <enabled />
  </timer>
  <timer name="fish timer2">
    <interval>1</interval>
    <script>
      for (repeat, 1, 40, 1) {
        rng = GetRandomInt(1,40)
        if (rng=1) {
          game.fishname = "largemouth bass"
          game.fishprice = "3"
        }
        if (rng=2) {
          game.fishname = "trout"
          game.fishprice = "0"
        }
        if (rng=3) {
          game.fishname = "bluegill"
          game.fishprice = "1"
        }
        if (rng=4) {
          game.fishname = "catfish"
          game.fishprice = "1"
        }
        if (rng=5) {
          game.fishname = "salmon"
          game.fishprice = "8"
        }
        if (rng=6) {
          game.fishname = "northern pike"
          game.fishprice = "11"
        }
        if (rng=7) {
          game.fishname = "perch"
          game.fishprice = "2"
        }
        if (rng=8) {
          game.fishname = "striped bass"
          game.fishprice = "3"
        }
        if (rng=9) {
          game.fishname = "crabfish"
          game.fishprice = "4"
        }
        if (rng=10) {
          game.fishname = "mini squid"
          game.fishprice = "6"
        }
        if (rng=11) {
          game.fishname = "mystery tuna"
          game.fishprice = "0"
        }
        if (rng=12) {
          game.fishname = "time cod"
          game.fishprice = "0"
        }
        if (rng=13) {
          game.fishname = "freezing fin"
          game.fishprice = "1"
        }
        if (rng=14) {
          game.fishname = "firetail tetra"
          game.fishprice = "2"
        }
        if (rng=15) {
          game.fishname = "golden perch"
          game.fishprice = "10"
        }
        if (rng=16) {
          game.fishname = "emerald goby"
          game.fishprice = "22"
        }
        if (rng=17) {
          game.fishname = "rainbow darter"
          game.fishprice = "7"
        }
        if (rng=18) {
          game.fishname = "sapphire cichlid"
          game.fishprice = "18"
        }
        if (rng=19) {
          game.fishname = "platinum piranha"
          game.fishprice = "15"
        }
        if (rng=20) {
          game.fishname = "diamond guppy"
          game.fishprice = "20"
        }
        if (rng=21) {
          game.fishname = "orange koi"
          game.fishprice = "10"
        }
        if (rng=22) {
          game.fishname = "ruby redfish"
          game.fishprice = "4"
        }
        if (rng=23) {
          game.fishname = "england fish"
          game.fishprice = "0"
        }
        if (rng=24) {
          game.fishname = "spiky pufferfish"
          game.fishprice = "0"
        }
        if (rng=25) {
          game.fishname = "raining tree shrimp"
          game.fishprice = "0"
        }
        if (rng=26) {
          game.fishname = "yellow shrimp"
          game.fishprice = "0"
        }
        if (rng=27) {
          game.fishname = "nerite snail"
          game.fishprice = "0"
        }
        if (rng=28) {
          game.fishname = "blue dart frog"
          game.fishprice = "1"
        }
        if (rng=29) {
          game.fishname = "angelic fin"
          game.fishprice = "14"
        }
        if (rng=30) {
          game.fishname = "giant lobster"
          game.fishprice = "6"
        }
        if (rng=31) {
          game.fishname = "streaming nova"
          game.fishprice = "12"
        }
        if (rng=32) {
          game.fishname = "tetra ripplefish"
          game.fishprice = "14"
        }
        if (rng=33) {
          game.fishname = "dragon eye"
          game.fishprice = "16"
        }
        if (rng=34) {
          game.fishname = "sailing fin"
          game.fishprice = "19"
        }
        if (rng=35) {
          game.fishname = "thunderous snake"
          game.fishprice = "2"
        }
        if (rng=36) {
          game.fishname = "crazy fish"
          game.fishprice = "0"
        }
        if (rng=37) {
          game.fishname = "bio-luminescent pike"
          game.fishprice = "50"
        }
        if (rng=38) {
          game.fishname = "tortoise manta"
          game.fishprice = "10"
        }
        if (rng=39) {
          game.fishname = "weather eel"
          game.fishprice = "20"
        }
        if (rng=40) {
          game.fishname = "sister lullaby"
          game.fishprice = "20"
        }
        if (RandomChance(11)) {
          fish.alias = ""+game.fishname
          fish.price = ""+game.fishprice
          CloneObjectAndMoveHere (fish)
        }
        else {
          foreach (object, GetDirectChildren (game.pov.parent)) {
            if (object.alias = ""+game.fishname) {
              object.parent = null
            }
          }
        }
      }
    </script>
    <enabled />
  </timer>
</asl>

Still dun believe, now you add mrangel's 2. Hiding all notification errors at UI Initialisation script into this game code, and it should start working without errors now, I hope, otherwise let me know


I had just wanted to know where the problem was so I could fix it, since it means I skipped over something. I don't know what. I had all sorts of errors that were not reading as errors to the game engine, and I have tracked them all down and corrected them one at a time, which is fantastic feeling, because it plays much more neatly now, even though I ended up breaking things up and down the process and having to fix even more than I would have, but I survived, and I will do it all again, as soon as I know exactly how to, why I should, and where the error is. However, I did add that eraser to my game. The first time, it didn't work because I typed it in myself, not into the game engine, but onto a text document in some unuseful font, and then copied and pasted it into the UIscript. I think it works, now, but I have yet to see the error message on the console. Still, if anyone can help me wit the meaning of the error message, I still want a clue.


Error running script: Error evaluating expression 'GetDirectChildren(game.pov.parent)': Collection was modified; enumeration operation may not execute.

This means that Quest was executing the line:

foreach (some variable, GetDirectChildren(game.pov.parent)) {

and when it came to the end of the loop, Quest examined the list to see which value the variable should be set to next, but found that the elements in the list had changed.

This causes foreach to break completely, because changing the list makes it lose track of which elements have already been processed.

If the foreach line is in your code, the answer is simply not to add or remove elements from the room during that loop.

If this is the loop in one of the core scope functions (which I think can happen if a timer triggers while the sidebars are getting their object lists), then solving it will be a bigger problem. I don't know of a reliable way to fix this, because we don't have the atomic operations necessary to synchronise a multithreaded game. The only suggestion I could give would be avoiding timers, but I think that's not always possible.


Mrangel, I like that answer.

I also like the scripts you introduced to us that would hopefully keep errors from showing up on the game screen. Thank you for that.


The subsequent errors in that list, "Value cannot be null", are just cascading errors. After the foreach failed, the function that called it returned null instead of a list; and the function that called it tried to use ListCombine on that value, causing another error. So that function returns null as well, and the function that calls it generates another error because it's trying to use functions that expect a list on a null value…

This means that you get a massive lump of error messages, but could actually be useful.
For example:

Error evaluating expression ListCombine(ScopeReachableNotHeldForRoom(room), ScopeReachableInventory()): Value cannot be null.Parameter name: collection

This tells us that the either ScopeReachableNotHeldForRoom or ScopeReachableInventory returned null unexpectedly; letting us know which function the initial foreach error was in. If you had the code for the ListCombine function, you could look at the parameters and see which one is named collection to find out where the error actually occurred. This is useful information when you get a huge slew of errors like this from your own code… but less useful here.

In this case, one other fix might be changing the core function. Maybe you could change:

foreach (some_variable, GetDirectChildren(game.pov.parent)) {

to

children = GetDirectChildren(game.pov.parent)
foreach (some_variable, children) {

I'm not sure, but that might insulate it from changes; because the list variable children won't magically change when objects are moved in/out of the room. In this case, it would only be a problem if the object was destroyed.


Why would it not magically change the list? Would objects that left the room mid-script be included? Or would objects which enter mid-script be included? Would both be not?


Why would it not magically change the list? Would objects that left the room mid-script be included? Or would objects which enter mid-script be included? Would both be not?

When the line:

children = GetDirectChildren(game.pov.parent)

is executed, it sets the variable children to be a list of objects currently in the room. That list is a variable now; it's not special. You can add or remove objects if you want, but it won't change unless you change it. So it basically takes a snapshot of what objects were in the room when that line runs - including objects that later moved out of the room, and not counting any that later moved in. (Objects that are destroyed will still be magically removed, because destroying an object removes it from all lists – that's one reason why destroying objects is prone to so many confusing problems)

There's a chance that this won't actually insulate it (I'm not 100% sure how the internal behaviour of GetDirectChildren works - it could return a reference to a list which is maintained internally, but I don't think so). In that case, you'd have to make it game.children instead. (setting an object attribute to a list or dictionary always creates a second copy of the list in memory because of the way the save system works. Dereferencing in Quest is kind of weird).


If I have time, I might change my codes, but, right now, Spines on Leothwold has your no visible error messages code. I should add that to SailRock Home, too. I still have to change the battery in my PC, before I do anything.


Log in to post a reply.

Support

Forums