Budibase/budibase · error

Features do not exist for planType=${planType}

Error message

Features do not exist for planType=${planType}

What it means

getOfflineFeatures looks up the plan's features in the hard-coded SELF_FEATURES table for self-hosted offline licenses. If the license's plan.type has no entry there (e.g. a cloud-only plan like Premium used on self host), this plain Error is thrown. It means the offline license references a plan that self host does not support.

Source

Thrown at packages/pro/src/sdk/licensing/licenses/features.ts:150

    Feature.AI_CUSTOM_CONFIGS,
    Feature.PWA,
    Feature.CUSTOM_APP_SCRIPTS,
    Feature.PDF,
    Feature.BUDIBASE_AI,
    Feature.RECAPTCHA,
    Feature.PKCE_OIDC,
    Feature.TRANSLATIONS,
    Feature.MICROFRONTEND,
  ],
}

export function getOfflineFeatures(planType: PlanType): Feature[] {
  function readFeatures(planFeatures: PlanFeatures): Feature[] {
    const quotas = planFeatures[planType]

    if (!quotas) {
      // e.g. Premium plan doesn't exist on self host
      throw new Error(`Features do not exist for planType=${planType}`)
    }

    return quotas
  }
  return readFeatures(SELF_FEATURES)
}

View on GitHub (pinned to a81a902e9a)

Solutions

  1. Use an offline license token whose plan type is valid for self host (e.g. the self-host tier for your subscription), not a cloud-only plan.
  2. Regenerate the offline token from the account portal for the correct plan/hosting combination.
  3. Upgrade Budibase/pro so the runtime's SELF_FEATURES map includes the plan type in the token.
  4. Check the planType value in the decoded license token to confirm which plan it grants.

Example fix

// before
const features = getOfflineFeatures(license.plan.type) // throws for Premium
// after
const SELF_PLAN_TYPES = Object.keys(SELF_FEATURES) as PlanType[]
if (!SELF_PLAN_TYPES.includes(license.plan.type)) {
  console.warn(`Plan ${license.plan.type} unsupported on self host — skipping offline features`)
} else {
  const features = getOfflineFeatures(license.plan.type)
}
Defensive patterns

Strategy: validation

Validate before calling

import { SELF_FEATURES } from "../licensing/licenses/features"
function planSupportedOnSelfHost(planType: PlanType): boolean {
  return Boolean(SELF_FEATURES[planType])
}
if (!planSupportedOnSelfHost(license.plan.type)) {
  throw new Error(`Plan ${license.plan.type} is not available on self host`)
}

Type guard

function hasSelfHostFeatures(planType: PlanType): planType is keyof typeof SELF_FEATURES {
  return Boolean(SELF_FEATURES[planType])
}

Try / catch

try {
  const license = await getOfflineLicense()
} catch (e) {
  if (e instanceof Error && e.message.startsWith("Features do not exist for planType=")) {
    // offline token uses a cloud-only plan — request a self-host token
  } else throw e
}

Prevention

When it happens

Trigger: Calling getOfflineFeatures(planType) (indirectly via enrichLicense → getOfflineLicense after verifyOfflineLicenseToken succeeds) with a PlanType that has no key in SELF_FEATURES.

Common situations: Applying an offline license token generated for a cloud plan (e.g. Premium/enterprise cloud-only tier) to a self-hosted installation; a PlanType added in a newer Budibase version but the running version's SELF_FEATURES map predates it (or vice versa — token from newer version, older runtime); hand-edited license tokens.

Related errors


AI-assisted analysis of Budibase/budibase@a81a902e9a (2026-08-29). Data as JSON: /api/errors/6c7aa945735f3817. Report an issue: GitHub.