gatsbyjs/gatsby · error

Couldn't find the specified offline inject script

Error message

Couldn't find the specified offline inject script

What it means

gatsby-plugin-offline appends a user-supplied script to the generated service worker (public/sw.js) when the plugin option `appendScript` is set. The build reads that file from disk with fs.readFileSync; if the read fails (ENOENT, EACCES, etc.), the thrown system error is caught and re-thrown as this generic message. It fires during `createPages` / the Workbox generateSW step, so it aborts the whole Gatsby build.

Source

Thrown at packages/gatsby-plugin-offline/src/gatsby-node.js:209

            `$1, debug: ${JSON.stringify(debug)}});`
          )
        fs.writeFileSync(swDest, swText)
      }

      const swAppend = fs
        .readFileSync(`${__dirname}/sw-append.js`, `utf8`)
        .replace(/%idbKeyValVersioned%/g, idbKeyValVersioned)
        .replace(/%pathPrefix%/g, pathPrefix)
        .replace(/%appFile%/g, appFile)

      fs.appendFileSync(`public/sw.js`, `\n` + swAppend)

      if (appendScript !== null) {
        let userAppend
        try {
          userAppend = fs.readFileSync(appendScript, `utf8`)
        } catch (e) {
          throw new Error(`Couldn't find the specified offline inject script`)
        }
        fs.appendFileSync(`public/sw.js`, `\n` + userAppend)
      }

      reporter.info(
        `Generated ${swDest}, which will precache ${count} files, totaling ${size} bytes.\n` +
          `The following pages will be precached:\n` +
          precachePages
            .map(path => path.replace(`${process.cwd()}/public`, ``))
            .join(`\n`)
      )
    })
}

const MATCH_ALL_KEYS = /^/
exports.pluginOptionsSchema = function ({ Joi }) {
  // These are the options of the v3: https://www.gatsbyjs.com/plugins/gatsby-plugin-offline/#available-options
  return Joi.object({

View on GitHub (pinned to 8b06340921)

Solutions

  1. Verify the file exists at the exact path passed to `appendScript` (run `ls -la <path>` from the project root, the same cwd Gatsby uses).
  2. Use a path relative to process.cwd() (project root), not relative to the plugin or to __dirname, e.g. options: { appendScript: './src/sw-inject.js' }.
  3. Check spelling and case of every path segment, especially when developing on macOS/Windows and deploying to Linux.
  4. If you no longer need a custom SW append, remove the `appendScript` option entirely (passing null is the default and skips the read).
  5. Confirm the Gatsby process has read permission on the file (chmod / ownership) in CI and Docker builds.

Example fix

// before (gatsby-config.js)
{
  resolve: `gatsby-plugin-offline`,
  options: { appendScript: `src/cust-sw.js` } // file was moved
}

// after
{
  resolve: `gatsby-plugin-offline`,
  options: { appendScript: `src/custom-sw-inject.js` } // matches actual file
}
Defensive patterns

Strategy: validation

Validate before calling

const fs = require('fs');
const path = require('path');
function assertAppendScriptExists(appendScript) {
  if (appendScript == null) return; // null/undefined is the safe default
  const resolved = path.isAbsolute(appendScript)
    ? appendScript
    : path.resolve(process.cwd(), appendScript);
  if (!fs.existsSync(resolved) || !fs.statSync(resolved).isFile()) {
    throw new Error(`gatsby-plugin-offline appendScript not found: ${resolved}`);
  }
}
// call before exporting gatsby-config plugins
assertAppendScriptExists(process.env.GATSBY_OFFLINE_APPEND_SCRIPT);

Type guard

function isAppendScriptPath(v) {
  return v == null || (typeof v === 'string' && v.trim().length > 0);
}

Try / catch

let userAppend;
try {
  userAppend = fs.readFileSync(appendScript, 'utf8');
} catch (e) {
  if (e.code === 'ENOENT') {
    reporter.panic(`appendScript not found at ${appendScript} (cwd: ${process.cwd()})`);
  }
  throw e;
}

Prevention

When it happens

Trigger: Setting the plugin option `appendScript` in gatsby-config.js to a path that does not resolve from the project root, e.g. { resolve: 'gatsby-plugin-offline', options: { appendScript: 'src/custom-sw.js' } } where the file is missing, mis-spelled, or outside the resolved cwd. It also triggers on unreadable files or paths that exist only in a different working directory than the build root.

Common situations: Renaming/deleting the injected SW script without updating gatsby-config.js; using a relative path that resolves differently in CI vs. local; typos in the option name or path; moving the file into a subfolder; case-sensitivity mismatches between macOS (case-insensitive) and Linux CI (case-sensitive).

Related errors


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