{"record":{"id":"8c95f6f3330e01f4","repo":"parcel-bundler/parcel","slug":"einval","errorCode":"EINVAL","errorMessage":"is not a symlink","messagePattern":"is not a symlink","errorType":"error_code","errorClass":"FSError","httpStatus":null,"severity":"error","filePath":"packages/core/fs/src/MemoryFS.js","lineNumber":550,"sourceCode":"  }\n\n  createWriteStream(filePath: FilePath, options: ?FileOptions): WriteStream {\n    return new WriteStream(this, filePath, options);\n  }\n\n  realpathSync(filePath: FilePath): FilePath {\n    return this._normalizePath(filePath);\n  }\n\n  // eslint-disable-next-line require-await\n  async realpath(filePath: FilePath): Promise<FilePath> {\n    return this.realpathSync(filePath);\n  }\n\n  readlinkSync(filePath: FilePath): FilePath {\n    let symlink = this.symlinks.get(filePath);\n    if (!symlink) {\n      throw new FSError('EINVAL', filePath, 'is not a symlink');\n    }\n    return symlink;\n  }\n\n  // eslint-disable-next-line require-await\n  async readlink(filePath: FilePath): Promise<FilePath> {\n    return this.readlinkSync(filePath);\n  }\n\n  async symlink(target: FilePath, path: FilePath) {\n    target = this._normalizePath(target);\n    path = this._normalizePath(path);\n    this.symlinks.set(path, target);\n    await this._sendWorkerEvent({\n      type: 'symlink',\n      path,\n      target,\n    });","sourceCodeStart":532,"sourceCodeEnd":568,"githubUrl":"https://github.com/parcel-bundler/parcel/blob/59484858a1a0bcbb71f74088956bb437a2db6505/packages/core/fs/src/MemoryFS.js#L532-L568","documentation":"Thrown by MemoryFS.readlinkSync() when the given filePath has no entry in the internal `symlinks` Map. MemoryFS stores symlinks separately from files and directories; readlink only consults the symlinks map. The error code EINVAL matches Node.js fs.readlink behavior for non-symlink paths.","triggerScenarios":"Calling `memoryFS.readlinkSync('/some/path')` where the path was never registered via `memoryFS.symlink(target, path)`, or where the symlink was deleted. Also triggered when code assumes a path is a symlink but it's actually a regular file or directory.","commonSituations":"A Parcel resolver traverses a path and calls readlink on every segment to detect symlinks, but some segments are regular files. Plugin code copies logic from NodeFS without checking `lstat().isSymbolicLink()` first. MemoryFS doesn't support lstatSync, so callers can't pre-check symlink type easily.","solutions":["Check `memoryFS.symlinks.has(filePath)` before calling readlinkSync when using MemoryFS directly.","Wrap readlinkSync in try/catch and treat EINVAL as 'not a symlink' by returning the path unchanged.","Use the OverlayFS wrapper which has `_isSymlink()` that safely checks both layers."],"exampleFix":"// before\nlet target = fs.readlinkSync(filePath);\n\n// after\nlet target;\ntry {\n  target = fs.readlinkSync(filePath);\n} catch (e) {\n  if (e.code !== 'EINVAL') throw e;\n  target = filePath; // not a symlink, return as-is\n}","handlingStrategy":"try-catch","validationCode":"// Check symlinks Map before readlinkSync (MemoryFS-specific)\nfunction safeReadlinkSync(fs, filePath) {\n  filePath = fs._normalizePath ? fs._normalizePath(filePath) : filePath;\n  if (fs.symlinks?.has(filePath)) {\n    return fs.readlinkSync(filePath);\n  }\n  return null; // not a symlink\n}","typeGuard":"// Guard: check if the filesystem exposes a symlinks Map\nfunction hasSymlinkMap(fs) {\n  return fs instanceof Object && fs.symlinks instanceof Map;\n}","tryCatchPattern":"try {\n  let target = fs.readlinkSync(filePath);\n} catch (e) {\n  if (e.code === 'EINVAL') {\n    // Not a symlink — proceed with regular file logic\n  } else {\n    throw e;\n  }\n}","preventionTips":["When traversing paths, only call readlink on paths known to be symlinks.","Wrap readlink in a helper that returns null for non-symlinks instead of throwing.","For OverlayFS, use its built-in _isSymlink() method which safely checks both layers."],"tags":["filesystem","memoryfs","symlink","readlink","einval"],"backgroundTag":null,"analyzedSha":"59484858a1a0bcbb71f74088956bb437a2db6505","analyzedAt":"2026-08-13T04:06:35.925Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}