gatsbyjs/gatsby · error

You must specify either a cache or a directory

Error message

You must specify either a cache or a directory

What it means

Thrown by fetchRemoteFile when the caller supplies neither a `cache` object (with a .directory) nor a `directory` string. The function needs a writable location to store the downloaded file, and this guard refuses to proceed before computing paths or touching the mutex/db.

Source

Thrown at packages/gatsby-core-utils/src/fetch-remote-file.ts:151

async function fetchFile({
  url,
  cache,
  directory,
  auth = {},
  httpHeaders = {},
  ext,
  name,
  cacheKey,
  excludeDigest,
}: IFetchRemoteFileOptions): Promise<string> {
  // global introduced in gatsby 4.0.0
  const BUILD_ID = global.__GATSBY?.buildId ?? ``
  const fileDirectory = (cache ? cache.directory : directory) as string
  const storage = getStorage(getDatabaseDir())

  if (!cache && !directory) {
    throw new Error(`You must specify either a cache or a directory`)
  }

  const fetchFileMutex = createMutex(`gatsby-core-utils:fetch:${url}`)
  await fetchFileMutex.acquire()

  // Fetch the file.
  try {
    const digest = createContentDigest(url)
    const finalDirectory = excludeDigest
      ? path.resolve(fileDirectory)
      : path.join(fileDirectory, digest)

    if (!name) {
      name = getRemoteFileName(url)
    }

    if (!ext) {
      ext = getRemoteFileExtension(url)

View on GitHub (pinned to 8b06340921)

Solutions

  1. Pass the Gatsby cache: fetchRemoteFile({ url, cache, ... }) — cache comes from the onCreateNode/etc. helper args and exposes .directory.
  2. Or pass an explicit directory string if you manage storage yourself.
  3. If you only need the bytes transiently, supply a temp directory under os.tmpdir().

Example fix

// before
await fetchRemoteFile({ url, ext, name })
// after (forward cache from node helpers)
await fetchRemoteFile({ url, ext, name, cache })
Defensive patterns

Strategy: validation

Validate before calling

if (!cache && !directory) throw new Error('cache or directory required')
await fetchRemoteFile({ url, cache, directory })

Type guard

const hasStorage = (o: { cache?: { directory: string }; directory?: string }): boolean =>
  !!o?.cache?.directory || typeof o?.directory === 'string'

Prevention

When it happens

Trigger: Calling fetchRemoteFile({ url, ... }) with both `cache` and `directory` omitted; passing cache as undefined and directory as undefined/null; integrating the helper directly (outside gatsby-source-*) and forgetting the storage option.

Common situations: Custom source plugins or scripts invoking fetchRemoteFile standalone without forwarding the Gatsby cache; refactoring a source plugin and dropping the cache arg; migrating from an older signature that defaulted directory.

Related errors


AI-assisted analysis of gatsbyjs/gatsby@8b06340921 (2026-08-13). Data as JSON: /api/errors/ea93fa8a9d77759a. Report an issue: GitHub.