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
- Verify the file exists at the exact path passed to `appendScript` (run `ls -la <path>` from the project root, the same cwd Gatsby uses).
- 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' }.
- Check spelling and case of every path segment, especially when developing on macOS/Windows and deploying to Linux.
- If you no longer need a custom SW append, remove the `appendScript` option entirely (passing null is the default and skips the read).
- 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
- Treat appendScript as build-critical config: lint gatsby-config.js to assert the file exists.
- Run gatsby build in CI with the same cwd you use locally.
- Add a prebuild check (npm script) that verifies referenced asset paths exist.
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
- Local plugin ${pluginName} requires a package.json file
- Failed to write out requires
- Could not find the file specified in the Link header `${head
- MissingInfoError
- Did not recognize ${curr}
AI-assisted analysis of gatsbyjs/gatsby@8b06340921 (2026-08-13).
Data as JSON: /api/errors/8c3238eb61bf7c8d.
Report an issue: GitHub.