moeru-ai/airi · error · Error

Cannot declare permissions for unknown plugin

Error message

Cannot declare permissions for unknown plugin "${extensionId}".

What it means

Thrown by PermissionService.declare when store.get(extensionId) is unset. The in-memory permission store is populated only by initialize(extensionId, declaration, options) during session setup; declare is strictly an incremental merge on top of an initialized snapshot, so calling it for a plugin the service has never initialized is a state-machine violation.

Solutions

  1. Initialize first: permissions.initialize(extensionId, declaration) (normally done by host.start) before any declare call.
  2. Ensure the exact same extensionId is used for initialize and declare — compare against session.extension.id.
  3. In tests/devtools, bootstrap via the host (start the extension) instead of hand-calling declare on a bare service.
  4. Guard the call: if (!permissions.get(extensionId)) initialize, then declare.

Example fix

// before
svc.declare('ext-1', { apis: [...] }) // fresh PermissionService -> throws

// after
svc.initialize('ext-1', { apis: [...] })
svc.declare('ext-1', { resources: [...] })
Defensive patterns

Strategy: validation

Validate before calling

// Before declare:
if (!permissions.get(extensionId)) {
  permissions.initialize(extensionId, requestedDeclaration)
  return
}
permissions.declare(extensionId, requestedDeclaration)

Type guard

const isPermissionStateInitialized = (svc: PermissionService, extensionId: string): boolean => svc.get(extensionId) !== undefined

Try / catch

try {
  svc.declare(extensionId, declaration)
} catch (error) {
  if (error instanceof Error && error.message.includes('unknown plugin')) {
    svc.initialize(extensionId, declaration) // first-time declaration doubles as init
    return
  }
  throw error
}

Prevention

When it happens

Trigger: Invoking permissions.declare('ext-1', ...) before the host started that extension (initialize runs during start); using a different extensionId string than the one passed to initialize (casing, versioned id); calling declare on a freshly constructed PermissionService/Host in tests without bootstrapping; declaring after the host was recreated.

Common situations: Test helpers that exercise declare/grant directly; devtools that mutate permissions before the target extension session exists; extensionId drift between manifest, session registration, and permission tooling; multiple host instances sharing nothing in-memory.

Related errors


AI-assisted analysis of moeru-ai/airi@677329427f (2026-08-18). Data as JSON: /api/errors/1b7d8525b02e11ca. Report an issue: GitHub.

Appendix: source

Thrown at packages/plugin-sdk/src/plugin-host/runtimes/shared/services/permissions.ts:322

    const persisted = options?.persisted ?? {}
    const explicitGrant = options?.grant ?? requested
    const mergedGrant = mergePermissions(persisted, explicitGrant)
    const granted = intersectPermissions(requested, mergedGrant)
    const previousRevision = this.store.get(extensionId)?.revision ?? 0
    const snapshot: PermissionSnapshot = {
      requested,
      granted,
      revision: previousRevision + 1,
    }

    this.store.set(extensionId, snapshot)
    return snapshot
  }

  declare(extensionId: string, requestedDeclaration: ModulePermissionDeclaration) {
    const existing = this.store.get(extensionId)
    if (!existing) {
      throw new Error(`Cannot declare permissions for unknown plugin "${extensionId}".`)
    }

    const requested = normalizeDeclaration(requestedDeclaration)
    const snapshot: PermissionSnapshot = {
      requested: mergePermissionDeclarations(existing.requested, requested),
      granted: existing.granted,
      revision: existing.revision + 1,
    }

    this.store.set(extensionId, snapshot)
    return snapshot
  }

  grant(extensionId: string, grant: ModulePermissionGrant) {
    const existing = this.store.get(extensionId)
    if (!existing) {
      throw new Error(`Cannot grant permissions to unknown plugin "${extensionId}".`)
    }

View on GitHub (pinned to 677329427f)