iOfficeAI/OfficeCLI · error · ArgumentException
--xml is required for replace
Error message
--xml is required for replace
What it means
Thrown when the action is 'replace' but the xml argument is null. Replace swaps each matched element with the provided fragment (node.ReplaceWith). Without a fragment there is nothing to replace with. This is a destructive action — the original element is removed and substituted.
Source
Thrown at src/officecli/Core/RawXmlHelper.cs:219
// AddAfterSelf inserts immediately after `node`, so calling it
// repeatedly against the SAME anchor REVERSES a multi-element
// fragment (start,end → node,end,start). Iterate in REVERSE and
// keep anchoring to `node`, mirroring insertbefore — each element
// lands right after `node`, yielding source order. (Chaining the
// anchor off the just-added node does NOT work: AddAfterSelf clones
// a parented element, so the loop variable still points at the
// detached fragment node, the chain breaks, and only the first
// element reaches the document — silently dropping the rest of a
// multi-marker fragment, e.g. a second tr-level bookmark.) A
// reversed start/end pair also desynced the id-balancer into
// duplicate bookmark ids.
foreach (var el in afterFragment.AsEnumerable().Reverse())
node.AddAfterSelf(el);
affected++;
break;
case "replace":
if (xml == null) throw new ArgumentException("--xml is required for replace");
var replaceFragment = ParseFragment(xml, xDoc);
node.ReplaceWith(replaceFragment.ToArray());
affected++;
break;
case "remove" or "delete":
RequireParent(node, "remove");
node.Remove();
affected++;
break;
case "setattr":
if (xml == null) throw new ArgumentException("--xml is required for setattr (format: name=value)");
var eqIdx = xml.IndexOf('=');
if (eqIdx <= 0) throw new ArgumentException("setattr format: name=value");
var attrName = xml[..eqIdx];
var attrValue = xml[(eqIdx + 1)..];
View on GitHub (pinned to 1ced45e900)
Solutions
- Provide a valid XML fragment to replace each matched element with.
- If you want to delete elements without substitution, use action='remove' instead of 'replace'.
- Ensure the replacement fragment is well-formed XML — it's parsed by ParseFragment before insertion.
Example fix
// before RawXmlHelper.Execute(root, xpath, "replace", null); // after RawXmlHelper.Execute(root, xpath, "replace", "<w:pPr><w:pStyle w:val=\"Title\"/></w:pPr>");
Defensive patterns
Strategy: validation
Validate before calling
if (action.Equals("replace", StringComparison.OrdinalIgnoreCase) && string.IsNullOrEmpty(xml))
throw new ArgumentException("--xml is required for replace");
RawXmlHelper.Execute(rootElement, xpath, action, xml); Try / catch
try
{
RawXmlHelper.Execute(rootElement, xpath, "replace", xml);
}
catch (ArgumentException ex) when (ex.Message == "--xml is required for replace")
{
Console.Error.WriteLine("Provide a replacement XML fragment. Use 'remove' if you want to delete without replacement.");
} Prevention
- Provide the replacement XML fragment for replace.
- Use 'remove' if you intended deletion without substitution.
- Validate that the replacement fragment is well-formed XML.
When it happens
Trigger: RawXmlHelper.Execute(rootElement, xpath, "replace", null). XPath matched at least one element, code entered the replace case, xml == null.
Common situations: Caller invokes raw-set with action=replace but omits --xml. Caller intended 'remove' (delete without substitution) instead of 'replace'. Conditionally-built xml argument evaluated to null.
Related errors
- --xml is required for append
- --xml is required for prepend
- --xml is required for insertbefore
- --xml is required for insertafter
- --xml is required for setattr (format: name=value)
AI-assisted analysis of iOfficeAI/OfficeCLI@1ced45e900 (2026-08-13).
Data as JSON: /api/errors/ff31fbaba6ae5500.
Report an issue: GitHub.