An Office service that supports add-ins to interact with objects in Office client applications.
Hi Rajat Bharadwaj,
Welcome to Microsoft Q&A Forum!
I completely understand the issue you are facing. It appears to be a limitation in how Office.context.document.getFileAsync packages the OOXML (.docx) file, particularly for images in headers when the document is in-memory or unsaved. The "ooxWord://" scheme you are seeing is an internal Word representation that hasn't been resolved to a standard relative path yet.
Here is a solution that implements this fix:
1. Save the Document Before Exporting
If the document hasn't been saved to disk (e.g., it's a new or modified unsaved file), the internal references may not resolve properly. Try saving it first to force Word to embed and update resources correctly:
- Prompt the user to save the document manually (via File > Save) before triggering the upload.
- Test if
getFileAsyncthen produces a valid package with correct rels (no "ooxWord://" or mismatches). - Note: There's no direct
saveAsyncAPI in Word's Office.js for automatic saving. If this is a frequent issue, consider checking the document's URL viaOffice.context.document.urlto see if it's saved (a non-empty URL indicates it's on disk/OneDrive).
If saving resolves it, integrate a user prompt or workflow step in your add-in.
2. Post-Process the OOXML Package
If forcing a save isn't feasible or doesn't solve it completely, you need to modify the compressed file client-side before uploading. You can use JSZipto unpack the file, fix the broken relationships in the headers, and repack it.
Note: Microsoft is providing this information as a convenience to you. These sites are not controlled by Microsoft, and Microsoft cannot make any representations regarding the quality, safety, or suitability of any software or information found there. Please ensure that you fully understand the risks before using any suggestions from the above link.
Here is the code implementation using JSZip:
async function fixHeaderImages(fileData) {
const zip = new JSZip();
await zip.loadAsync(fileData);
// Iterate over potential header rels files (header1.xml.rels, header2.xml.rels, etc.)
// Adjust loop limit based on expected max headers in your documents
for (let i = 1; i <= 10; i++) {
const relsPath = `word/_rels/header${i}.xml.rels`;
if (zip.file(relsPath)) {
let relsXml = await zip.file(relsPath).async('string');
// Parse the XML (use DOMParser for browser compatibility)
const parser = new DOMParser();
const xmlDoc = parser.parseFromString(relsXml, 'application/xml');
// Find all image relationships
const relationships = xmlDoc.getElementsByTagName('Relationship');
for (let rel of relationships) {
const type = rel.getAttribute('Type');
// Check if it is an image relationship
if (type === 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/image') {
let target = rel.getAttribute('Target');
// Check for the specific broken schema
if (target && target.startsWith('ooxWord://word/media/imageheader')) {
// Extract number (e.g., "1" from "imageheader1.png")
const match = target.match(/imageheader(\d+)\.png/);
if (match) {
const num = match[1];
// Update to internal relative path (assumes renaming strips "header" and keeps number)
rel.setAttribute('Target', `../media/image${num}.png`);
rel.removeAttribute('TargetMode'); // Defaults to internal
}
}
}
}
// Serialize back to string
const serializer = new XMLSerializer();
relsXml = serializer.serializeToString(xmlDoc);
// Replace the file in the zip
zip.file(relsPath, relsXml);
}
}
// Generate the fixed zip as ArrayBuffer
const fixedFileData = await zip.generateAsync({ type: 'arraybuffer', compression: 'DEFLATE' });
// Now base64-encode fixedFileData to send to your API
const base64 = btoa(String.fromCharCode.apply(null, new Uint8Array(fixedFileData)));
return base64;
}
// Usage in your getFileAsync callback:
// fixHeaderImages(result.value).then(base64 => {
// // Call your REST API with the fixed base64 string
// });
This code explicitly handles the logic where imageheaderX.png is renamed to imageX.png and ensures the XML relationship points to the correct relative path (../media/).
Hope this helps!
If the answer is helpful, please click "Accept Answer" and kindly upvote it. If you have extra questions about this answer, please click "Comment".
Note: Please follow the steps in our documentation to enable e-mail notifications if you want to receive the related email notification for this thread.