moeru-ai/airi · error · Error
Extension packages can contain only files and directories
Error message
Extension packages can contain only files and directories: ${relativePath} What it means
Entries that are neither regular files nor directories (checked after the symlink check) are rejected. Extension packages must contain only plain files and directories so the staged copy and size accounting behave deterministically.
Solutions
- Delete special files (sockets/FIFOs) from the folder: `find . ! -type f ! -type d` to list them.
- Stop the process that created the socket/pipe (dev server) and clean up before importing.
- Copy only regular files into a clean directory and import that.
- Check for leftover artifacts in build output directories and exclude them.
Example fix
// before: folder contains ipc.sock (unix socket)
await staged('my-ext/') // -> throws
// after: clean special files
// find my-ext -not -type f -not -type d -delete
await staged('my-ext/') Defensive patterns
Strategy: validation
Validate before calling
import { readdir } from 'node:fs/promises'
import { join } from 'node:path'
async function findSpecialFiles(dir: string): Promise<string[]> {
const out: string[] = []
for (const entry of await readdir(dir, { withFileTypes: true })) {
const p = join(dir, entry.name)
if (!entry.isFile() && !entry.isDirectory() && !entry.isSymbolicLink()) out.push(p)
else if (entry.isDirectory()) out.push(...await findSpecialFiles(p))
}
return out
} Try / catch
try {
await staged(folder)
} catch (error) {
if (error instanceof Error && error.message.includes('only files and directories')) {
showUserError('Remove sockets/FIFOs/device files from the package folder.')
return
}
throw error
} Prevention
- Stop dev servers before importing; leftover .sock/.pid artifacts are rejected.
- Clean build output directories of runtime artifacts before packaging.
- Run `find <dir> ! -type f ! -type d` as a pre-import hygiene check.
When it happens
Trigger: Calling inspectExtensionDirectory on a folder containing FIFOs, Unix sockets, device files, or other special filesystem objects anywhere in the tree.
Common situations: A running dev server left a .sock file inside the package folder; a test created a named pipe in the output directory; someone copied a /dev device node into the folder; tmpfs artifacts inside the source tree.
Related errors
- Extension package exceeds the
- Extension packages cannot contain symbolic links
- Extension source must be a regular directory
- Extension source must be a regular directory
- Extension entrypoint escapes the package folder
AI-assisted analysis of moeru-ai/airi@438a067dde (2026-09-17).
Data as JSON: /api/errors/07614f636f04f9f1.
Report an issue: GitHub.
Appendix: source
Thrown at apps/stage-tamagotchi/src/main/services/airi/plugins/host/directory-import.ts:191
for await (const entry of entries) {
entryCount += 1
if (entryCount > extensionPackageLimits.entries) {
throw new Error(`Extension package exceeds the ${extensionPackageLimits.entries} entry limit.`)
}
const path = join(directory, entry.name)
const stats = await lstat(path)
const relativePath = relative(sourceRealPath, path)
if (stats.isSymbolicLink()) {
throw new Error(`Extension packages cannot contain symbolic links: ${relativePath}`)
}
if (stats.isDirectory()) {
directories.push(relativePath)
pendingDirectories.push(path)
continue
}
if (!stats.isFile()) {
throw new Error(`Extension packages can contain only files and directories: ${relativePath}`)
}
totalBytes += stats.size
if (totalBytes > extensionPackageLimits.totalBytes) {
throw new Error('Extension package exceeds the 512 MiB size limit.')
}
files.push({ path, relativePath, size: stats.size })
}
}
directories.sort()
files.sort((left, right) => left.relativePath.localeCompare(right.relativePath))
const manifestRelativePath = relative(sourceRealPath, manifestPath)
const manifestFile = files.find(file => file.relativePath === manifestRelativePath)
if (!manifestFile) {
throw new Error(`Extension manifest does not exist: ${manifestPath}`)
}
if (manifestFile.size > extensionPackageLimits.manifestBytes) {View on GitHub (pinned to 438a067dde)