{"record":{"id":"67355f3ff7877cde","repo":"garrytan/gstack","slug":"cannot-resolve-path-filepath","errorCode":null,"errorMessage":"Cannot resolve path: ${filePath}","messagePattern":"Cannot resolve path: (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"browse/src/path-security.ts","lineNumber":111,"sourceCode":"    }\n  }\n  const isSafe = SAFE_DIRECTORIES.some(dir => isPathWithin(realPath, dir));\n  if (!isSafe) {\n    throw new Error(`Path must be within: ${SAFE_DIRECTORIES.join(', ')}`);\n  }\n}\n\n/** Validate a file path for remote serving (GET /file). TEMP_DIR only, not cwd. */\nexport function validateTempPath(filePath: string): void {\n  const resolved = path.resolve(filePath);\n  let realPath: string;\n  try {\n    realPath = fs.realpathSync(resolved);\n  } catch (err: any) {\n    if (err.code === 'ENOENT') {\n      throw new Error('File not found');\n    }\n    throw new Error(`Cannot resolve path: ${filePath}`);\n  }\n  const isSafe = TEMP_ONLY.some(dir => isPathWithin(realPath, dir));\n  if (!isSafe) {\n    throw new Error(`Path must be within: ${TEMP_ONLY.join(', ')} (remote file serving is restricted to temp directory)`);\n  }\n}\n\n/** Escape special regex metacharacters in a user-supplied string to prevent ReDoS. */\nexport function escapeRegExp(s: string): string {\n  return s.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\n}\n","sourceCodeStart":93,"sourceCodeEnd":123,"githubUrl":"https://github.com/garrytan/gstack/blob/94993f74012782fd94416dd44b8314f6363a13a4/browse/src/path-security.ts#L93-L123","documentation":"Thrown by validateTempPath when realpathSync fails with an errno other than ENOENT (e.g., EACCES). The file may exist but the browse process cannot resolve its real path due to permissions or a broken symlink in TEMP_DIR, so the raw 'Cannot resolve path' error is surfaced.","triggerScenarios":"Requesting a temp file whose path cannot be resolved: permission denied on a path component, a broken symlink in TEMP_DIR, or an I/O error reading the directory.","commonSituations":"Permission mismatch between the browse process and the file owner (file written by a different user); broken symlink leftover in TEMP_DIR; filesystem corruption or transient I/O error.","solutions":["Check permissions on the file and every component of the path: `namei -l <path>`","Remove broken symlinks in TEMP_DIR: `find <TEMP_DIR> -xtype l -delete`","Regenerate the file so it is owned by the current browse process","If the file is from another user, copy it into a fresh temp path owned by this process"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"import * as fs from 'fs';\n\nfunction isResolvableTempPath(p: string): boolean {\n  try { fs.realpathSync(p); return true; }\n  catch (e: any) { return e.code !== 'ENOENT' ? false : false; }\n}\n\n// Distinguish ENOENT (caught as 'File not found') from other errors\nfunction tempPathStatus(p: string): 'ok' | 'missing' | 'unresolvable' {\n  try { fs.realpathSync(p); return 'ok'; }\n  catch (e: any) {\n    if (e.code === 'ENOENT') return 'missing';\n    return 'unresolvable';\n  }\n}","typeGuard":"function isReadableTempFile(p: string): boolean {\n  try { fs.realpathSync(p); fs.accessSync(p, fs.constants.R_OK); return true; } catch { return false; }\n}","tryCatchPattern":"try {\n  return serveTempFile(filePath);\n} catch (e: any) {\n  if (/Cannot resolve path/.test(e.message)) {\n    return { status: 500, body: 'Temp file exists but cannot be resolved (permissions or broken symlink)' };\n  }\n  throw e;\n}","preventionTips":["Run writer and reader as the same user so permissions match","Clean broken symlinks in TEMP_DIR before serving","Regenerate artifacts in the current process rather than reusing files from another user","Use fs.accessSync(R_OK) to preflight before serving"],"tags":["filesystem","permissions","remote-serving","temp-dir","errno"],"backgroundTag":null,"analyzedSha":"94993f74012782fd94416dd44b8314f6363a13a4","analyzedAt":"2026-08-12T04:06:23.140Z","schemaVersion":2},"datasetVersion":"2026-08-12T13:17:24.610Z"}