moeru-ai/airi · error · Error

does not exist

Error message

${label} does not exist: ${path}

What it means

assertRegularFile lstats a required path (e.g. an extension manifest) and rethrows missing-file errors as '<label> does not exist: <path>'. It runs during extension directory inspection to verify the package layout before import.

Solutions

  1. Point the import at the directory that directly contains the manifest file
  2. Confirm the file named in the error exists at the printed path
  3. Re-extract the extension package if files are missing

Example fix

// before
importFromDirectory('/Downloads/myext') // manifest is in /Downloads/myext/extension
// after
importFromDirectory('/Downloads/myext/extension')
Defensive patterns

Strategy: try-catch

Validate before calling

import { lstat } from 'node:fs/promises'
async function manifestExists(dir: string): Promise<boolean> {
  try { await lstat(`${dir}/package.json`); return true } catch { return false }
}

Try / catch

try {
  await importFromDirectory(dir)
} catch (e) {
  if (e instanceof Error && /does not exist:/.test(e.message)) {
    console.warn(`${e.message} — select the folder that directly contains the manifest`)
    return promptUserForCorrectFolder()
  }
  throw e
}

Prevention

When it happens

Trigger: inspectExtensionDirectory is called on a directory whose package.json (or other required file, per label) is absent at the given path.

Common situations: User selects the wrong folder (parent or sibling of the actual extension); extension zip extracted without its root folder; manifest renamed or deleted after selection.

Understand the failure class

Background: "File not found" and ENOENT errors: why libraries can't find a file that should exist — this error's family across 50 libraries.

Related errors


AI-assisted analysis of moeru-ai/airi@438a067dde (2026-09-17). Data as JSON: /api/errors/ca65b5906e4feb7f. Report an issue: GitHub.

Appendix: source

Thrown at apps/stage-tamagotchi/src/main/services/airi/plugins/host/directory-import.ts:110

      exposure: kit.exposure,
    })),
    ...(manifest.kits?.uses ?? []).map(kit => ({
      direction: 'uses' as const,
      id: kit.id,
      version: kit.version,
      optional: kit.optional ?? false,
    })),
  ]
}

async function assertRegularFile(path: string, label: string): Promise<Stats> {
  let stats: Stats
  try {
    stats = await lstat(path)
  }
  catch (error) {
    if (isMissingPathError(error)) {
      throw new Error(`${label} does not exist: ${path}`)
    }
    throw error
  }

  if (stats.isSymbolicLink() || !stats.isFile()) {
    throw new Error(`${label} must be a regular file: ${path}`)
  }
  return stats
}

async function readManifestSnapshot(path: string, expectedSize: number): Promise<Buffer> {
  const handle = await open(path, 'r')
  try {
    // One extra byte distinguishes the maximum valid manifest from a file
    // that grew past the limit after the directory walk.
    const buffer = Buffer.allocUnsafe(extensionPackageLimits.manifestBytes + 1)
    let bytesRead = 0
    while (bytesRead < buffer.byteLength) {

View on GitHub (pinned to 438a067dde)