CoplayDev/unity-mcp · error · InvalidOperationException
Screenshot folder '{folderOverride}' resolves outside the Un
Error message
Screenshot folder '{folderOverride}' resolves outside the Unity project root ('{fullFolder}'). Use a project-relative path (e.g. 'Assets/Screenshots' or 'Captures'). What it means
Thrown by ResolveFolderAbsolute when the resolved screenshot folder path escapes the Unity project root. This is a deliberate security guard against path traversal. The method computes the full path and checks it starts with the project root; anything outside (absolute paths elsewhere, or relative paths using '..' that traverse up) is rejected.
Source
Thrown at MCPForUnity/Runtime/Helpers/ScreenshotUtility.cs:654
string projectRoot = GetProjectRootPath().TrimEnd('/');
string requested = string.IsNullOrWhiteSpace(folderOverride) ? DefaultFolder : folderOverride.Trim();
requested = requested.Replace('\\', '/').TrimEnd('/');
string combined = Path.IsPathRooted(requested)
? requested
: Path.Combine(projectRoot, requested);
string fullFolder = Path.GetFullPath(combined).Replace('\\', '/').TrimEnd('/');
string normalizedRoot = projectRoot;
// Reject paths that escape the project root (case-insensitive on Windows, exact elsewhere).
var rootComparison = Application.platform == RuntimePlatform.WindowsEditor
? StringComparison.OrdinalIgnoreCase
: StringComparison.Ordinal;
if (!fullFolder.Equals(normalizedRoot, rootComparison) &&
!fullFolder.StartsWith(normalizedRoot + "/", rootComparison))
{
throw new InvalidOperationException(
$"Screenshot folder '{folderOverride}' resolves outside the Unity project root ('{fullFolder}'). " +
$"Use a project-relative path (e.g. 'Assets/Screenshots' or 'Captures').");
}
return fullFolder;
}
/// <summary>
/// Converts an absolute filesystem path inside the project to a project-relative path
/// (forward slashes, no leading separator). Returns the input unchanged when it does
/// not live under the project root.
/// </summary>
public static string ToProjectRelativePath(string normalizedFullPath)
{
if (string.IsNullOrEmpty(normalizedFullPath)) return normalizedFullPath;
string projectRoot = GetProjectRootPath();
string normalized = normalizedFullPath.Replace('\\', '/');
if (normalized.StartsWith(projectRoot, StringComparison.OrdinalIgnoreCase))View on GitHub (pinned to c21bf496bc)
Solutions
- Use a project-relative path like 'Assets/Screenshots' or 'Captures'.
- If you need screenshots outside the project, capture to a project folder then copy/move the file externally afterward.
- Avoid absolute paths and '..' traversal in folderOverride.
- Ensure the folder name does not contain backslashes on Windows that confuse path resolution (use forward slashes).
Example fix
// before
params = {"folderOverride": "/tmp/screenshots"}
// after
params = {"folderOverride": "Assets/Screenshots"} Defensive patterns
Strategy: validation
Validate before calling
import os
def validate_folder_in_project(folder: str, project_root: str) -> bool:
"""Returns True if the resolved folder is within the project root."""
if os.path.isabs(folder):
combined = folder
else:
combined = os.path.join(project_root, folder)
full = os.path.normpath(combined)
root = os.path.normpath(project_root)
return full == root or full.startswith(root + os.sep) Try / catch
try
{
string folder = ResolveFolderAbsolute(folderOverride);
}
catch (InvalidOperationException ex) when (ex.Message.Contains("resolves outside the Unity project root"))
{
return new ErrorResponse("Use a project-relative path like 'Assets/Screenshots'.");
} Prevention
- Always use project-relative paths for screenshot folders.
- Never use absolute paths or '..' traversal in folderOverride.
- Use forward slashes in paths for cross-platform consistency.
- If screenshots need to go elsewhere, capture in-project then move the file.
When it happens
Trigger: Passing a folderOverride with '../' sequences that resolve outside the project, an absolute path to a different directory (e.g. '/tmp' or 'C:\Users'), or a symlink that points outside the project root.
Common situations: AI passes an absolute temp path thinking it's convenient; user wants screenshots in a shared external folder; relative path with too many '..' levels; path normalization differences between platforms (symlinks, junction points).
Related errors
- Could not generate a unique screenshot filename for '{fullPa
- provider returned a disallowed file type '.{ext}'
- Unsafe zip entry rejected: {name}
- Unsafe zip entry escapes destination: {name}
- Selected folder does not exist.
AI-assisted analysis of CoplayDev/unity-mcp@c21bf496bc (2026-08-13).
Data as JSON: /api/errors/377544a8a9d98753.
Report an issue: GitHub.