moeru-ai/airi · error · Error

Cannot grant permissions to unknown plugin "${extensionId}".

Error message

Cannot grant permissions to unknown plugin "${extensionId}".

What it means

Thrown by `PermissionRegistry.grant()` when no permission snapshot exists for the given `extensionId`. Granting is an incremental operation that intersects a new grant with an existing snapshot's requested ceiling, so the extension must already have been initialized via `initialize()`. The store miss is checked before any grant merging or intersection logic runs.

Source

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

    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}".`)
    }

    const mergedGranted = mergePermissions(existing.granted, grant)
    const snapshot: PermissionSnapshot = {
      requested: existing.requested,
      granted: intersectPermissions(existing.requested, mergedGranted),
      revision: existing.revision + 1,
    }
    this.store.set(extensionId, snapshot)
    return snapshot
  }

  get(extensionId: string) {
    return this.store.get(extensionId)
  }

  isAllowed(extensionId: string, area: ModulePermissionArea, action: string, key: string) {
    const snapshot = this.store.get(extensionId)

View on GitHub (pinned to 27111382b4)

Solutions

  1. Ensure `permissions.initialize(extensionId, requestedDeclaration)` runs before any `grant()` for the same extension id.
  2. Check `permissions.get(extensionId)` before granting, and initialize if absent (the grant will then be intersected with the requested ceiling).
  3. Confirm the extension id string matches exactly what was used at registration.
  4. On store reset/reload, replay the initialize step before granting.

Example fix

// before
permissions.grant(extensionId, grant)

// after
if (!permissions.get(extensionId)) {
  permissions.initialize(extensionId, requestedCeiling)
}
permissions.grant(extensionId, grant)
Defensive patterns

Strategy: validation

Validate before calling

if (!permissions.get(extensionId)) {
  permissions.initialize(extensionId, requestedCeiling)
}
permissions.grant(extensionId, grant)

Type guard

function isPermissionInitialized(extensionId: string): boolean {
  return permissions.get(extensionId) !== undefined
}

Try / catch

try {
  permissions.grant(extensionId, grant)
} catch (e) {
  if (e instanceof Error && e.message.includes('Cannot grant permissions to unknown plugin')) {
    permissions.initialize(extensionId, requestedCeiling)
    permissions.grant(extensionId, grant)
    return
  }
  throw e
}

Prevention

When it happens

Trigger: Calling `permissions.grant(extensionId, grant)` before `permissions.initialize(extensionId, ...)` has created a snapshot for that extension. Also caused by a typo or scope mismatch in the extension id, or by granting after the store was cleared (reload/test) without re-initializing.

Common situations: Permission-prompt flow that grants in response to a user action before the extension's permission record was seeded; host code that reuses a stale extension id after a plugin reload into a fresh store; tests that call grant directly.

Related errors


AI-assisted analysis of moeru-ai/airi@27111382b4 (2026-08-12). Data as JSON: /api/errors/c35c06f2e4c6c62d. Report an issue: GitHub.