iOfficeAI/OfficeCLI · error · ArgumentException
Invalid skill file path: {relativePath}
Error message
Invalid skill file path: {relativePath} What it means
Thrown by LoadSkillFile when any segment of the split relative path is '..' or '.', rejecting path traversal and current-directory segments to contain reads inside the skill folder. The guard prevents escaping the skill's embedded-resource prefix. ArgumentException echoing the original (pre-normalized) relativePath.
Source
Thrown at src/officecli/Core/SkillInstaller.cs:293
/// <summary>
/// Return the text content of one bundled reference file inside a skill
/// (e.g. "reference/decision-rules.md"). Shared by the CLI
/// `load_skill <name> --path <rel>` command and the MCP
/// `load_skill` tool's path= argument. Throws on unknown skill, path
/// traversal, a binary asset (cannot ride the text channel), or a missing
/// file.
/// </summary>
public static string LoadSkillFile(string skillName, string relativePath)
{
if (!SkillMap.TryGetValue(skillName, out var folder))
throw new ArgumentException($"Unknown skill: {skillName}. Available: {KnownSkillsList()}");
var rel = (relativePath ?? "").Replace('\\', '/').TrimStart('/');
if (rel.Length == 0)
throw new ArgumentException("path is empty — pass a relative skill file, e.g. reference/decision-rules.md");
// Contain to the skill folder: reject traversal and current-dir segments.
if (rel.Split('/').Any(seg => seg is ".." or "."))
throw new ArgumentException($"Invalid skill file path: {relativePath}");
if (BinarySkillExtensions.Contains(Path.GetExtension(rel)))
throw new ArgumentException(
$"'{rel}' is a binary asset and cannot be served over the text channel. " +
$"Install the skill to get it on disk: officecli skills install {skillName}");
var content = LoadEmbeddedResource($"skills/{folder}/{rel}");
if (content == null)
throw new ArgumentException(
$"Skill file not found: {rel}. List available files via the manifest at the end of: " +
$"officecli load_skill {skillName}");
return content;
}
/// <summary>
/// Build the "Reference files" manifest appended to a SKILL.md. Deep trees
/// (≥ 3 path segments, e.g. a 52-directory style library) collapse to one
/// line per second-level directory so the manifest stays compact; shallow
/// files (reference/foo.md) are listed individually. Empty string when the
/// skill bundles nothing beyond SKILL.md.View on GitHub (pinned to 1ced45e900)
Solutions
- Use a direct relative path inside the skill folder (e.g. 'reference/foo.md').
- To read another skill's files, call LoadSkillFile with that skill's name instead of traversing.
- Strip leading './' before calling; '..' is never valid here.
Example fix
// before load_skill morph-ppt --path ../xlsx-toolkit/reference/rules.md // after load_skill xlsx-toolkit --path reference/rules.md
Defensive patterns
Strategy: validation
Validate before calling
var rel = relativePath.Replace('\\', '/').TrimStart('/');
if (rel.Split('/').Any(seg => seg is ".." or "."))
throw new ArgumentException($"Invalid skill file path: {relativePath}");
var text = SkillInstaller.LoadSkillFile(skillName, rel); Try / catch
try { var text = SkillInstaller.LoadSkillFile(skillName, relativePath); }
catch (ArgumentException ex) when (ex.Message.Contains("Invalid skill file path"))
{ /* reject traversal; use a direct in-skill path */ } Prevention
- Never use '..' or '.' segments — target files directly within the skill folder.
- To read another skill's files, switch the skillName rather than traversing.
- Sanitize user-supplied paths before passing them in.
When it happens
Trigger: Passing a path containing '..' (e.g. '../other/SKILL.md', 'reference/../../etc') or '.' segments. The skill-name check and empty-path check already passed.
Common situations: A caller tries to read another skill's files via relative traversal, or a path built by concatenation accidentally includes a '.' or '..' segment.
Related errors
- Image file '{path}' has extension .{ext} but magic bytes ind
- Unknown skill: {skillName}. Available: {KnownSkillsList()}
- path is empty — pass a relative skill file, e.g. reference/d
- Property 'sqref' (or 'range'/'ref') is required for validati
- Batch input must be a JSON array. Got: {rootKind.ToString().
AI-assisted analysis of iOfficeAI/OfficeCLI@1ced45e900 (2026-08-13).
Data as JSON: /api/errors/c7514fb6167b95f0.
Report an issue: GitHub.