Search code examples
javascriptjquerysharepoint-2013office365apioffice-js

General Exception Error from word-win32-16.00.js:19:150094)\n at yi


I have a 100 or so Word Open XML (.xml, not .docx, saved as "Word XML Document")documents (components) stored on SharePoint.

I use AJAX to load these by selection, as xml, 1 to many into an array, in which I also manage the selection sequence.

Once the user has selected the "components" they can then insert them into Word, the insertion is done via an array traversal (there is probably a better way to do this - but for now it does work),

wordBuild does the loading

function writeDocSync(){
  // run through nameXMLArray to find the right sequence
  var x = 0;
  var countXMLAdds = 0;
  //debugger;
  toggleWriteButton("disable");
  $('.progress-button').progressInitialize("Building Word");
  toggleProgressBar(true);
  // only run if we have data present
  if(nameXMLArray.length > 0){
    // increment through sequentially until we have all values
    while (countXMLAdds <= checkedList.length){
      // repeatedly traverse the array to get the next in sequence
      while (x < nameXMLArray.length){
        if (Number(nameXMLArray[x].position) === countXMLAdds && nameXMLArray[x].useStatus === true){
          progHold = countXMLAdds;
          wordBuild(nameXMLArray[x].xml, nameXMLArray[x].filename, countXMLAdds);
        }
        x++;
      }
      x=0;
      countXMLAdds ++;
    }
    document.getElementById("showCheck").className = "results";
    writeSelections("<b>You just built your proposal using<br/>the following components:</b><br/>");
    toggleWriteButton("enable");
  }
}

xxxxxxxxx

function wordBuild(xmlBody, nameDoc, progress){ 
  var aryLN = checkedList.length;
  var progPCT = (progress/aryLN)*100;
  progressMeter.progressSet(progPCT);
  Word.run(function (context) {
    var currentDoc = context.document; 
    var body = currentDoc.body;
    body.insertOoxml(xmlBody, Word.InsertLocation.end);
    body.insertBreak(Word.BreakType.page, Word.InsertLocation.end);
    return context.sync().then(function () {
      showNotification("Written " + nameDoc);
    });
  })
  .catch(function (error) {
    showNotification('Error: ' + nameDoc + ' :' + JSON.stringify(error));
    if (error instanceof OfficeExtension.Error) {
      showNotification('Debug info: ' + JSON.stringify(error.debugInfo));
    }
  });
}

All the documents will load singly, and all will load in batches of say 10 - 30 or more.

The problem comes when I load the entire set (I have a "check all" option). Sometimes 50 will build before I get an exception, sometimes 60, rarely more than 60, but very occasionally I get a gap where the exception doesn't occur, then it continues later.

The exception (which is repeated for each file) is:

Debug info: {} Error: componentABC.xml :{"name":"OfficeExtension.Error","code":"GeneralException","message":"An internal error has occurred.","traceMessages":[],"debugInfo":{},"stack":"GeneralException: An internal error has occurred.\n at Anonymous function (https://customerportal.sharepoint.com/sites/components/Shared%20Documents/componentAssembler/Scripts/Office/1/word-win32-16.00.js:19:150094)\n at yi (https://customerportal.sharepoint.com/sites/components/Shared%20Documents/componentAssembler/Scripts/Office/1/word-win32-16.00.js:19:163912)\n at st (https://customerportal.sharepoint.com/sites/components/Shared%20Documents/componentAssembler/Scripts/Office/1/word-win32-16.00.js:19:163999)\n at d (https://customerportal.sharepoint.com/sites/components/Shared%20Documents/componentAssembler/Scripts/Office/1/word-win32-16.00.js:19:163819)\n at c (https://customerportal.sharepoint.com/sites/components/Shared%20Documents/componentAssembler/Scripts/Office/1/word-win32-16.00.js:19:162405)"}

Any help with what might cause this would be hugely appreciated.

Oh I should also say, the files where the exception is raised don't get inserted into Word. But in smaller batches - they work without issue.


Solution

  • I ended up using jQuery deferreds, I was already using jQuery for treeview and checkboxes etc. so it made sense.

    This is a mix of Geoffrey's suggestions and my own! I cannot claim it to be good code, only that is does work. (If it is good code or not will take me more time to understand!)

    I run batches of 49 xml doc inserts, at 51 the Async call "Word.run" failed in tests, and inserts of 80 or so documents in one Word.run caused Word to freeze, so although not proven 49 inserts within 1 Word.run seems like a good starter for 10! 50 inserts of 49 pieces allows for 2450 inserts, which is way beyond anything I can see being needed, and would probably break Word!

    To get the deferreds and sent variables to keep their values once launched as asynch deferreds I had to create a variable to transfer both new deferreds, and values, so I could use the "bind" command. As Word async returns context.sync() I check the count of the batch, when the batch is completed, I then call the next batch - inside the context.sync()

    A sort of recursive call, still a combination of Geoffrey's suggestion, and batches. This has a theoretical limit of 50 batches of 49 document sections. So far this has worked in all tests.

    The progress meter exists in its own timed call, but as JavaScript prioritises code over UI it does hop. For example 120 documents it will hop just below half way fairly quickly, then a while later jump to almost complete, then complete (effectively 3 hops of a massively fast sequential percentage increases, various tricks suggested have zero effect (forceRepaint() is the latest experiment!).

            function startUILock(){
                // batch up in groups of 49 documents (51 and more were shown to fail, 49 gives manouvre room)
                toggleProgressBar(true);
                $('.progress-button').progressInitialize("Building Word");
                progressMeter.progressSet(1);   
                $.blockUI({message: "Building word..."});
                setTimeout(forceRepaint, 3000);
            }
    
            function forceRepaint(){
                var el = document.getElementById('progDiv');
                el.style.cssText += ';-webkit-transform:rotateZ(0deg)';
                el.offsetHeight;
                el.style.cssText += ';-webkit-transform:none';
            }
    
            function UIUnlock(insertedCount){
                debugger;
                var pct = (insertedCount/checkedList.length)*100
                  //showNotification('Progress percent is: ' + pct);
                if (insertedCount !== checkedList.length ){  
                  progressMeter.progressSet(pct);
                  forceRepaint();
                } else {
                $.unblockUI();
                progressMeter.progressSet(100); 
                }
            }
    
            function writeDocDeffered(){
                insertedCounter = 0;
                var lastBatch = 0;
                var x = 49;
                var z = checkedList.length + 1;
                if(x > z){
                        x=z;
                }
                deferreds = buildDeferredBatch(x, lastBatch);
                $.when(deferreds).done(function () {    
                        return;
                    })
                    .fail(function () {
                       //showNotification('One of our promises failed');
                    });
            }
    
            function buildDeferredBatch(batch, lastBatch) {
                // this ensures the variables remain as issued - allows use of "bind"
                var deferredsa = [];
                                var docSender = {
                                    defr : $.Deferred(),                        
                                    POSITION: batch,
                                    LASTPOSITION: lastBatch,
                                    runMe : function(){                                     
                                    this.defr.resolve(writeDocBatchedDeferred(this.POSITION, this.LASTPOSITION, this.defr));
                                    }
                                }
                                // small timeout might not be required
                                deferredsa.push(setTimeout(docSender.runMe.bind(docSender), 10));                                                               
                return deferredsa;
            }
    
            function writeDocBatchedDeferred(batch, lastBatch, defr){
                // write the batches using deferred and promises
                var x;
                var countXMLAdds = lastBatch; 
                x = 0;
                var fileName;
                debugger;   
                // only run if we have data present
                if(nameXMLArray.length > 0){
                var aryLN = checkedList.length;
                // increment through sequentially until we have all values  
                    Word.run(function (context) {
                    var currentDoc = context.document; 
                    var body = currentDoc.body; 
                    while (countXMLAdds <= batch){      
                        // repeatedly traverse the array to get the next in sequence
                        while (x < nameXMLArray.length){                
                            if (Number(nameXMLArray[x].position) === countXMLAdds && nameXMLArray[x].useStatus === true){  
                                fileName = nameXMLArray[x].filename;
                                body.insertOoxml(nameXMLArray[x].xml, Word.InsertLocation.end);
                                body.insertBreak(Word.BreakType.page, Word.InsertLocation.end);
                                insertedCounter = countXMLAdds;                     
                                var latest = insertedCounter;
                                var timerIt = {                                         
                                    LATEST: latest,         
                                    runMe : function(){ 
                                    UIUnlock(this.LATEST);
                                    }
                                }
                                setTimeout(timerIt.runMe.bind(timerIt),1000);                                   
                            }
                        x++;    
                        }
                        x=0;
                        countXMLAdds ++;
                    }
                    return context.sync().then(function () {                            
                        if(countXMLAdds = batch){
                            var lastBatch = batch + 1;
                            // set for next batch
                            var nextBatch = batch + 50;
                            var totalBatch = checkedList.length + 1;
                            // do not exceed the total batch
                            if(nextBatch > totalBatch){
                                nextBatch=totalBatch;
                            }
                            // any left to process keep going
                            if (nextBatch <= totalBatch && lastBatch < nextBatch){
                                deferreds =  deferreds.concat(buildDeferredBatch(nextBatch, lastBatch));                            
                            } 
                            // this batch done
                            defr.done();                
                        }
                    });
                    })
                    .catch(function (error) {
                    showNotification('Error: ' + nameXMLArray[x].filename + " " + JSON.stringify(error));
                    if (error instanceof OfficeExtension.Error) {
                        showNotification('Debug info: ' + JSON.stringify(error.debugInfo));
                    }
                }); 
                    document.getElementById("showCheck").className = "results";
                    writeSelections("<b>You just built your document using<br/>the following components:</b><br/>");
                }
                return defr.promise;
            }