Tencent/WeKnora · error
invalid source path: %w
Error message
invalid source path: %w
What it means
CopyFile wraps the error from secutils.SafePathUnderBase for the SOURCE path when it does not resolve inside baseDir — the same traversal guard GetFile applies. The copy is refused before reading anything. The wrapped error identifies the path violation.
Source
Thrown at internal/application/service/file/local.go:176
// The destination uses the same layout as SaveFile (baseDir/{tenantID}/{knowledgeID}/{unique}{ext}),
// and the copy is a real byte-for-byte copy (no hardlink) so deleting the source
// never affects it. Returns ErrCrossBackendCopy when srcPath is not a local path.
func (s *localFileService) CopyFile(ctx context.Context,
srcPath string, tenantID uint64, knowledgeID string,
) (string, error) {
// Only local paths are accepted. A provider scheme other than local://
// (e.g. s3://, minio://) means a cross-backend copy, which this service
// does not support. Legacy bare/absolute paths have no scheme and pass.
if i := strings.Index(srcPath, "://"); i >= 0 && srcPath[:i+3] != localScheme {
return "", fmt.Errorf("local file service cannot copy %q: %w", srcPath, ErrCrossBackendCopy)
}
// Validate and resolve the source path under baseDir (same guard as GetFile).
srcCandidate := s.normalizePathForBase(srcPath)
srcResolved, err := secutils.SafePathUnderBase(s.baseDir, srcCandidate)
if err != nil {
logger.Errorf(ctx, "Path traversal denied for CopyFile src: %v", err)
return "", fmt.Errorf("invalid source path: %w", err)
}
// Build destination path with the knowledge-owned layout.
dir := filepath.Join(s.baseDir, fmt.Sprintf("%d", tenantID), knowledgeID)
if _, err := secutils.SafePathUnderBase(s.baseDir, dir); err != nil {
logger.Errorf(ctx, "Path traversal denied for CopyFile dir: %v", err)
return "", fmt.Errorf("invalid path: %w", err)
}
if err := os.MkdirAll(dir, 0o755); err != nil {
return "", fmt.Errorf("failed to create directory: %w", err)
}
ext := filepath.Ext(srcPath)
filename := fmt.Sprintf("%d%s", time.Now().UnixNano(), ext)
dstPath := filepath.Join(dir, filename)
src, err := os.Open(srcResolved)
if err != nil {View on GitHub (pinned to 988cbb0330)
Solutions
- Ensure the source is the relative local:// path originally returned by SaveFile
- Re-baseline stored paths after any baseDir change (migration script stripping the old prefix)
- Reject '..'/absolute paths at the API layer before invoking CopyFile
- Verify LOCAL_STORAGE_BASE_DIR matches the one used when the source was saved
Example fix
// before: legacy absolute path stored in DB src := record.StoragePath // /var/data/old/uploads/a.pdf // after: migrate to relative path at read time src := strings.TrimPrefix(record.StoragePath, oldBaseDir) copied, err := localSvc.CopyFile(ctx, src, tenantID, knowledgeID)
Defensive patterns
Strategy: validation
Validate before calling
func validSourcePath(p string) bool {
return p != "" && !filepath.IsAbs(p) && !strings.Contains(p, "..") &&
(!strings.Contains(p, "://") || strings.HasPrefix(p, "local://"))
} Try / catch
copied, err := svc.CopyFile(ctx, src, tenantID, kid)
if err != nil {
if errors.Is(err, secutils.ErrPathTraversal) {
return fmt.Errorf("bad source path: %w", err)
}
return err
} Prevention
- Migrate stored paths after any baseDir change so they stay relative
- Never copy from client-supplied path strings; use stored local:// paths
- Validate source paths before calling CopyFile
- Keep LOCAL_STORAGE_BASE_DIR identical across deployments
When it happens
Trigger: Calling CopyFile with a source path containing '..' escaping baseDir, an absolute path outside baseDir, a bare legacy path that normalizes outside the base, or a path from a differently-configured instance.
Common situations: Legacy DB rows with absolute paths predating a baseDir change; client-supplied source paths passed through unvalidated; baseDir moved (e.g. /var/data -> /data) making old stored paths resolve outside the new base.
Related errors
- invalid path: %w
- invalid file path: %w
- invalid source path: %w
- path %q is outside this install's skill directory (%s); an i
- invalid file path: %w
AI-assisted analysis of Tencent/WeKnora@988cbb0330 (2026-09-02).
Data as JSON: /api/errors/61d4b550db4d7137.
Report an issue: GitHub.