remix-run/remix · error · AssetServerCompilationError
FILE_NOT_ALLOWED
FILE_NOT_ALLOWED
Error message
File "${identityPath}" is not allowed by the asset server access configuration. Add a matching allowFiles or allowPackages rule, or remove a conflicting denyFiles rule. What it means
The asset server compiler resolves each requested file to an identity path and then checks it against the access configuration (`allowFiles`/`allowPackages`/`denyFiles` rules) before generating a stable URL. If `args.isAllowed(identityPath)` returns false, compilation fails with FILE_NOT_ALLOWED — this is an explicit access-control rejection, not a missing file.
Source
Thrown at packages/assets/src/lib/files/compiler.ts:561
let identityPath = resolveExistingFilePath(filePath)
if (!identityPath) {
throw createAssetServerCompilationError(`File not found: ${filePath}`, {
code: 'FILE_NOT_FOUND',
})
}
if (!isServedFilePath(identityPath, args.extensions)) {
throw createAssetServerCompilationError(`File type is not supported: ${identityPath}`, {
code: 'FILE_NOT_SUPPORTED',
})
}
if (!args.isAllowed(identityPath)) {
throw createAssetServerCompilationError(
`File "${identityPath}" is not allowed by the asset server access configuration. ` +
`Add a matching allowFiles or allowPackages rule, or remove a conflicting denyFiles rule.`,
{
code: 'FILE_NOT_ALLOWED',
},
)
}
let stableUrlPathname = args.routes.toUrlPathname(identityPath)
if (!stableUrlPathname) {
throw createAssetServerCompilationError(
`File ${identityPath} is outside all configured mounts.`,
{
code: 'FILE_OUTSIDE_MOUNTS',
},
)
}
return {
identityPath,
stableUrlPathname,
}View on GitHub (pinned to 9696913134)
Solutions
- Add an allowFiles glob or allowPackages rule matching the file's identity path
- Check for a conflicting denyFiles rule that matches the path and remove/narrow it
- Verify the identity path spelling (relative form, extension) against your rule globs — mismatches silently fail the allow check
Example fix
// before
files({ allowFiles: ['app/assets/**'], denyFiles: ['**/*.secret'] })
// after
files({ allowFiles: ['app/assets/**', 'app/private-assets/logo.svg'], denyFiles: ['**/*.secret'] }) Defensive patterns
Strategy: validation
Validate before calling
// Mirror the compiler's check before building:
const identityPath = toIdentityPath(filePath)
if (!isAllowedByConfig(identityPath, { allowFiles, allowPackages, denyFiles })) {
// add rule or exclude the file from the build instead of failing later
} Type guard
function isAllowedByConfig(path: string, cfg: AccessConfig): boolean {
if (cfg.denyFiles.some((g) => match(g, path))) return false
return cfg.allowFiles.some((g) => match(g, path)) || cfg.allowPackages.some((p) => path.startsWith(p))
} Try / catch
try {
const resolved = compiler.resolvedFile(file)
} catch (error) {
if (error?.code === 'FILE_NOT_ALLOWED') {
// surface a config-specific message listing matching deny rules
}
throw error
} Prevention
- Keep allow/deny globs in one reviewed config file
- Add a CI test that every servable directory matches at least one allow rule and no deny rule
When it happens
Trigger: Requesting/serving a file whose identity path matches no `allowFiles`/`allowPackages` rule, or matches a `denyFiles` rule, in the asset server configuration. Triggered when the compiler resolves a served file (via `resolvedFile`) for a route/import that references the file.
Common situations: Adding new source files outside the allowed directories (e.g. importing from a package or path not covered by allowPackages); a security-hardened config that denies dotfiles/node_modules and a new import hits the deny rule; misconfigured globs in allowFiles that don't match the actual case or extension of the file.
Related errors
- FILE_OUTSIDE_MOUNTS
- FILE_TRANSFORM_RESULT_INVALID
- hmr must create a channel with a close function
- basePath must be a string
- fingerprint.buildId must be a string
AI-assisted analysis of remix-run/remix@9696913134 (2026-08-27).
Data as JSON: /api/errors/ba558f08c9840e80.
Report an issue: GitHub.