vxcontrol/pentagi · error
path must be relative (no leading /)
Error message
path must be relative (no leading /)
What it means
ResolveCachedPath normalizes the request path (backslashes to slashes, filepath.Clean) and rejects absolute paths. Absolute paths could escape the per-flow sandbox directory, so any path starting with '/' (or a Windows drive after cleaning) is rejected. Callers must supply a path relative to the flow data directory.
Source
Thrown at backend/pkg/flowfiles/files.go:103
func FlowUploadsDir(dataDir string, flowID uint64) string {
return filepath.Join(FlowDataDir(dataDir, flowID), UploadsDirName)
}
func FlowContainerDir(dataDir string, flowID uint64) string {
return filepath.Join(FlowDataDir(dataDir, flowID), ContainerDirName)
}
func FlowResourcesDir(dataDir string, flowID uint64) string {
return filepath.Join(FlowDataDir(dataDir, flowID), ResourcesDirName)
}
func ResolveCachedPath(dataDir string, flowID uint64, reqPath string) (string, error) {
if strings.TrimSpace(reqPath) == "" {
return "", errors.New("path query parameter is required")
}
cleaned := filepath.Clean(filepath.FromSlash(strings.ReplaceAll(reqPath, "\\", "/")))
if filepath.IsAbs(cleaned) {
return "", fmt.Errorf("path must be relative (no leading /)")
}
parts := strings.SplitN(cleaned, string(filepath.Separator), 2)
if parts[0] != UploadsDirName && parts[0] != ContainerDirName && parts[0] != ResourcesDirName {
return "", fmt.Errorf("path must start with '%s', '%s', or '%s'", UploadsDirName, ContainerDirName, ResourcesDirName)
}
flowDataDir := FlowDataDir(dataDir, flowID)
absPath := filepath.Join(flowDataDir, cleaned)
if !IsWithinDir(absPath, flowDataDir) {
return "", fmt.Errorf("path escapes the flow data directory")
}
return absPath, nil
}
func SanitizeFileName(fileName string) (string, error) {View on GitHub (pinned to ea665308ba)
Solutions
- Strip the leading '/' and send only the relative portion, e.g. 'uploads/report.pdf' instead of '/uploads/report.pdf'
- If you have an absolute path returned by another API, compute the relative portion (strip the flow data dir prefix) before calling
- On Windows-style input, remove drive letters and convert backslashes to forward slashes
Example fix
// before const p = '/uploads/report.pdf'; // after const p = 'uploads/report.pdf';
Defensive patterns
Strategy: validation
Validate before calling
if (reqPath.startsWith('/') || /^[a-zA-Z]:/.test(reqPath)) throw new Error('path must be relative'); Type guard
const isRelativePath = (p: string): boolean => !p.startsWith('/') && !/^[a-zA-Z]:[\\/]/.test(p); Try / catch
try {
const resolved = await api.resolveCachedPath(flowID, reqPath);
} catch (e) {
if (e.message.includes('path must be relative')) {
reqPath = reqPath.replace(/^([a-zA-Z]:)?[\\/]+/, '');
// retry with the stripped relative path
}
} Prevention
- Store and transmit only flow-relative paths, never absolute ones
- Strip leading slashes/drive letters at the boundary where paths enter your client code
- Never paste absolute container paths into path fields; use the server-returned relative path
When it happens
Trigger: Calling ResolveCachedPath / AddResourceFromFlow with a path like '/uploads/x.png', an absolute filesystem path pasted by the user, or a path constructed with a leading separator on either OS.
Common situations: Client concatenates a server-provided absolute path with the endpoint base URL; a user pastes an absolute container path into a UI field; Windows-style paths like 'C:\\...' that Clean turns absolute.
Related errors
- path must not contain parent directory traversal
- path escapes the flow data directory
- path must be relative
- path query parameter is required
- Token.CreationDisabled
AI-assisted analysis of vxcontrol/pentagi@ea665308ba (2026-09-01).
Data as JSON: /api/errors/9e826aec9d59640e.
Report an issue: GitHub.