We were getting the error, “The value 1 is not found in the map”, in one of our rather complex processes in AX 2012. It occurred only sometimes, which made debugging difficult, but finally I managed to track it down. The cause lies in something that many people use, therefore it’s possible that you will, or already did, run into the same problem.
I found the issue in AX 2012 R2 CU7 and reproduced it also in AX 2012 R3.
The problem can be demonstrated by running the following piece of code. It creates a progress bar, waits for some time and calls incCount() to update the progress. The last call to incCount() throws the error.
SysOperationProgress progress; #AviFiles progress = SysOperationProgress::construct(); progress.setAnimation(#AviUpdate); progress.setCaption("Some caption"); sleep((progress.updateInterval() + 1) * 1000); // The progress form gets initialized here. progress.incCount(); // Wait for more than 10 seconds sleep(11000); progress.incCount();
You see that there is nothing suspicious going on – I just simulate a process that runs for some time and occasionally updates the progress. I’ll explain the important of waiting a little bit later.
If you debug the code, you’ll find that the error is thrown at line 33 of SysOperationProgressBase.updateTime(). It’s this line:
r3 = totalValue.lookup(1)-progress;
It should be clear what happens in this code – it tries to get the value for the key 1 from totalValue map but it doesn’t exist (→ The value 1 is not found in the map).
Why the map doesn’t contain the key? It occurs that the initialization is done in setTotal(), which isn’t called in the code above. Therefore if you always call setTotal() when creating SysOperationProgress, you won’t ever get into this problem. Nevertheless you have to do it even if you actually don’t know the total – then you have to set it to zero:
It’s also worth noting that setTotal() gets called if you create the instance by SysOperationProgress::newGeneral(), which developers often do anyway.
Nevertheless why the error occurs only sometimes? The SysOperationProgressBase class usually checks whether the key exists in the map before trying to use it. The exception is – obviously – in updateTime() and several conditions must be met before this piece of code gets called. The most tricky one is this:
if (time-laptime > #tenSeconds)
It must be ten seconds since the last update and if it took less, this code doesn’t get executed and no error is thrown. Therefore we got this error as a side effect of something slowing the system down. Now it’s also clear why my script waits for more than ten seconds before calling incCount() again.
Always calling setTotal() is a relatively easy workaround, but it would be better if SysOperationProgress handled the problem in a better way. It should either accept that the value 1 doesn’t have to exist in totalValue (and check if it’s there before using it) or it should throw an error to inform the developer that he’s trying to use an object that hasn’t been properly initialized.
This blog post doesn’t suggest that The value 1 is not found in the map is always caused by a progress bar – it may refer to any other map. Nevertheless it’s one of things that you may want to check.
This post really helped me last year. Was using progress bar in AX 2009 🙂
Martin, next time you’re in the UK drop me a line, I owe you a beer, I was chasing this little bugger for 5 hours, safety wrapped all my map handling code, still not avail… And then this… Pfff.