Troubleshooting

What goes wrong most often, why, and how to fix it. Each problem has one line on why and one fix; open More for the rest.

Start with bb doctor. It checks your machine, and in a project the project and its Storyblok space, and gives the exact steps for each thing that’s missing:

npx -y @ef-global/backbase doctor

bb doctor

Doctor shows every check in a table, with the steps under each that fails or warns: they’re the steps below, word for word. A failure stops /backbase:new before it makes anything; a warning stops nothing. After a fix, run bb doctor again. Each check’s id links here, as #<id>.

On Windows

bb doctor and bb create find both .exe programs and .cmd shims on your PATH, including npm, npx, pnpm and Claude Code, and paths may contain spaces. If an older bb says npm isn't on PATH though npm --version works, or rejects a GitHub Packages token that works with npm, update bb and run doctor again. When a command times out, bb stops its child processes too.

node: Node is too old

Fails. Why: bb runs on Node 20 and up, and doctor says Node 18.19.0 is older than 20, with your version.

Fix: install Node 22 (LTS), then open a new terminal.

Doctor’s steps
  1. Install Node 22 (LTS) from https://nodejs.org, or with nvm: nvm install 22 && nvm alias default 22
  2. Open a new terminal and check it: node --version

git: git isn’t installed

Fails. Why: bb create clones and commits with git. Doctor says git isn't on PATH, or git is on PATH, but git --version fails.

Fix: install git, then open a new terminal.

Doctor’s steps
  1. Install git: on macOS run xcode-select --install, otherwise see https://git-scm.com/downloads
  2. Open a new terminal and check it: git --version

bb-binary: another bb on your PATH

Warns. Why: the bb on your path is another program, often Babashka, or another version. It matters only when you type bb yourself: the plugin runs Backbase’s through npx.

Fix: Run Backbase’s bb through npx: npx -y @ef-global/backbase <command>

More

When there’s no bb on your path at all, it passes. When the bb there is Babashka, an unrelated Clojure tool with the same name, or another program that doesn’t print a version:

  • Run Backbase’s bb through npx: npx -y @ef-global/backbase <command>
  • Or add it to the project, so the plugin uses that one: npm install --save-dev @ef-global/backbase
  • Or put Backbase’s bb first on PATH: npm install -g @ef-global/backbase, then make sure npm’s global bin folder (npm prefix -g, then /bin) comes before the other bb’s folder. which -a bb lists them in order

When it’s another version of Backbase’s bb:

  • Install this version: npm install -g @ef-global/backbase@<version>
  • Or run it through npx: npx -y @ef-global/backbase <command>

github: not signed in to GitHub

Fails. Why: the plugin and the boilerplate both live in ef-global on GitHub. Doctor says gh isn't signed in to GitHub, gh isn't installed, and neither GH_TOKEN nor GITHUB_TOKEN is set, or gh auth status didn't answer in time.

Fix: gh auth login

Doctor’s steps
  1. Install the GitHub CLI if you haven’t: https://cli.github.com (on macOS: brew install gh)
  2. Sign in: gh auth login
  3. Check it: gh auth status

When doctor says GitHub doesn't accept the token in GH_TOKEN, gh is using a token from your environment that doesn’t work. The same goes for GITHUB_TOKEN:

  1. Replace or unset GH_TOKEN, then sign in: gh auth login
  2. Check it: gh auth status

github-ssh: SSH to GitHub fails

Warns. Why: bb create clones over HTTPS instead, through gh’s sign-in, so you can leave it.

Fix: Connect once and accept GitHub’s host key: ssh -T git@github.com

More

Doctor says ssh isn't on PATH when there’s no SSH at all: there’s nothing to fix then. When it says github.com isn't a known host on this machine yet:

  • Connect once and accept GitHub’s host key: ssh -T git@github.com

When GitHub doesn’t accept an SSH key from this machine, or SSH didn’t sign in or didn’t answer in time:

  1. Create a key if you have none: ssh-keygen -t ed25519 -C <your email>
  2. Add it to GitHub: gh ssh-key add ~/.ssh/id_ed25519.pub
  3. If ef-global uses single sign-on, choose Configure SSO next to the key on https://github.com/settings/keys and authorise ef-global
  4. Check it: ssh -T git@github.com

packages-token: npm can’t read @ef-global

Fails. Why: Backpack and bb install from GitHub Packages with GH_PACKAGES_TOKEN, and it isn’t set, or GitHub Packages refuses it: wrong or expired (E401), without read:packages or single sign-on (E403), or its account may not be in ef-global (E404).

Fix: create a classic token with read:packages, and export it as GH_PACKAGES_TOKEN in your shell profile.

Doctor’s steps
  1. Create a personal access token (classic) with the read:packages scope: https://github.com/settings/tokens/new?scopes=read:packages&description=Backbase
  2. If ef-global uses single sign-on, choose Configure SSO next to the token and authorise ef-global
  3. Export it in your shell profile (~/.zshrc or ~/.bashrc): export GH_PACKAGES_TOKEN=<your token>
  4. Open a new terminal, start Claude Code from it and run bb doctor again. Never paste the token into a chat with an agent

When doctor says npm isn't on PATH:

  1. Install Node 22 (LTS) from https://nodejs.org: npm comes with it
  2. Open a new terminal and check it: npm --version

When it says GitHub Packages didn't answer within 10 seconds:

  • Check your network or VPN, then run bb doctor again

figma-mcp: Figma isn’t connected

Skips neutrally when unseen. Why: doctor can see a local Figma connector or plugin, but not a claude.ai connector, so it says Figma: checked when the frame is read, with the hint “Add a Figma connector in your agent’s settings and sign in.”

Fix: nothing until reading the frame fails. Then sign in to Figma in the agent you use.

More

A detected connector or plugin passes. A local MCP that needs authentication doesn’t warn: your claude.ai connector can still work. bb doctor --write leaves this check out.

If the frame read fails, check the Figma connector in the agent you are using and sign in there. For a local Claude Code MCP, run claude mcp login figma (use your server’s name), then start a new session. For a claude.ai connector, reconnect Figma in claude.ai.

storyblok-token: no Storyblok token

Warns. Why: doctor says STORYBLOK_OAUTH_TOKEN isn't set. Only a write to Storyblok needs it, so this can wait. In a project, a token in .env passes this check: Covered by the project's .env (STORYBLOK_OAUTH_TOKEN).

Fix: see Setting the Storyblok token.

Doctor’s steps

With the token set, bb create writes it to the new project’s .env.

  1. In Storyblok, open My account, then Personal access token, and create one
  2. Put it in your project’s .env as this line: STORYBLOK_OAUTH_TOKEN=<your token>
  3. Or export it in your shell profile (~/.zshrc or ~/.bashrc): export STORYBLOK_OAUTH_TOKEN=<your token>, then open a new terminal. A shell export overrides the project’s .env
  4. Run bb doctor again in the project. Never paste the token into a chat with an agent

page-browser: bb has no browser

Warns. Why: bb’s Chromium isn’t in its cache yet, so bb page measure and compare can’t open a page. Doctor says bb's Chromium <version> isn't in bb's browser cache, <folder>, so bb page measure and compare can't open a page.

Fix: Run bb page browser install: it downloads about 120 MB into <folder>, and changes neither the project nor Playwright’s shared cache

More

Only measuring and comparing a page need it. A project whose own Playwright has its Chromium passes: bb uses it first, and it’s the project’s to install. A project’s Playwright without its Chromium is passed over, and doctor says so. A Playwright on your PATH never counts.

  1. Run bb page browser install: it downloads about 120 MB into <folder>, and changes neither the project nor Playwright’s shared cache
  2. Run bb doctor again

Don’t add Playwright to the project for bb, and don’t run npx playwright install: in Playwright’s shared cache, an install deletes the browsers it thinks unused, which other projects use.

When doctor says bb's playwright-core is missing, bb’s own install is incomplete:

  1. Install bb again: npm install -g @ef-global/backbase, or run it with npx @ef-global/backbase
  2. Run bb doctor again

When doctor says bb can’t tell, its playwright-core names a Chromium revision per platform, and only Playwright knows this machine’s:

  1. Run bb page browser install: Playwright installs Chromium only when it isn’t there yet
  2. Run bb page measure: it says when Chromium won’t start

See bb’s browser.

The checks below look at the project you run bb doctor in, and its Storyblok space. Outside a project they skip, and say why. Where a step names a file, <project> is your project’s folder.

project-backpack: Backpack missing or too old

Fails. Why: doctor says @ef-global/backpack isn't installed in node_modules, or Backpack 3.9.0 is installed, and Backbase supports Backpack 4 only.

Fix: Install the project’s packages, in the project’s folder: npm ci

Doctor’s steps
  1. Install the project’s packages, in the project’s folder: npm ci
  2. If npm can’t read @ef-global packages, fix packages-token first
  3. Run bb doctor again

When Backpack is older than 4:

  1. Move the project to Backpack 4: set @ef-global/backpack to ^4 in package.json, then npm install
  2. Run bb doctor again

project-chaperone: Chaperone isn’t set up

Fails. Why: Chaperone can’t run Backbase’s preset in this project, and doctor names what’s missing. Outside a Backpack project, it skips.

Fix: bb doctor --write

More

What doctor can find missing:

  • .chaperone.json is missing, doesn’t extend the Backbase preset, or lacks a supported version pin (minimum 0.12.0). An older Chaperone fails every schema on schema-name-matches-folder (why), and doctor says so.
  • component-map.exceptions.json is missing. Without it, Chaperone reports Cannot check registration, which no baseline can record: chaperone baseline exits 2.
  • package.json doesn’t have @ef-global/backbase as a dev dependency.
  • @ef-global/backbase isn’t installed in node_modules, so Chaperone stops with preset file not found and checks nothing.
  • It’s installed without its CLI, node_modules/@ef-global/backbase/dist/cli.js, so each of the preset’s three command rules says @ef-global/backbase isn't installed in this project: run npx @ef-global/backbase doctor --write.

bb doctor --write (or --fix) adds the preset and the pin to .chaperone.json, keeping existing rules, other extends and newer pins; creates component-map.exceptions.json as {} when there’s none, never overwriting one; pins @ef-global/backbase to the running bb in devDependencies, moving a pin out of dependencies; and installs it with the package manager the lockfile names (npm install --save-dev --save-exact @ef-global/backbase@<version>, or pnpm add, yarn add or bun add). The install reads GitHub Packages, so it needs GH_PACKAGES_TOKEN, runs before doctor’s other checks, and when it fails, doctor shows the package manager’s error. Invalid JSON in .chaperone.json is reported, never replaced. Run it again and it changes nothing. The path needs its leading ./:

{
  "chaperoneVersion": "0.12.0",
  "extends": ["./node_modules/@ef-global/backbase/chaperone/backbase.json"]
}

A bb that isn’t a release, such as one built from a branch, can’t pin itself:

  1. This bb (<version>) isn’t a release, so it can’t pin itself. Add @ef-global/backbase to devDependencies at the release you use
  2. Then run bb doctor --write to set up .chaperone.json and component-map.exceptions.json

When package.json asks for a range, a tag or a path, doctor doesn’t choose a version for you:

  1. Install what package.json asks for, @ef-global/backbase@<range>: npm install, or the install of the package manager the lockfile names
  2. Then run bb doctor --write to set up .chaperone.json and component-map.exceptions.json, when either is missing

Warns when the installed bb isn’t the one you’re running:

  • package.json pins an older bb: bb doctor --write raises the pin and installs it.
  • It pins a newer bb: doctor never lowers a pin. npx @ef-global/backbase in the project runs the installed one.
  • It pins a release, and you’re running a prerelease, such as 0.19.0-next.0: doctor won’t raise a release pin to a prerelease. Pin it yourself, then run bb doctor --write.
  • node_modules doesn’t hold the pinned version: bb doctor --write installs it.
  • It asks for a range, a tag or a path: that’s the project’s choice. Pin the version you want, then run bb doctor --write.

See the Chaperone preset for the rules. Chaperone 0.12.0 is pinned and tested against the stock boilerplate.

project-prettierignore: Prettier checks build output

Warns. Why: Chaperone runs prettier --check ., which reads only .prettierignore, so without .next, .turbo and node_modules there it lints Next’s build cache.

Fix: Add .next, .turbo and node_modules to .prettierignore (bb doctor --write does too).

More

bb doctor --write and --fix add the missing lines under # Backbase, keeping the file’s own lines, or create the file.

project-launch: preview can’t start the site

Warns. Why: .claude/launch.json has no configuration for the project’s dev server, so Claude’s preview pane can’t start the site.

Fix: bb doctor --write

More

bb reads the server from package.json’s dev script, with the package manager the lockfile names, on the port the script gives (-p 3000, -p3000, --port=3000, PORT=3000), or 3000 for a plain next dev, with an https url for --experimental-https. In the boilerplate that’s npm run dev at https://localhost:3000. It skips with no dev script, or a port only the environment knows (-p $PORT).

bb doctor --write and --fix add { "name": "dev", "runtimeExecutable": "npm", "runtimeArgs": ["run", "dev"], "port": 3000, "url": "https://localhost:3000" } to the file’s configurations, keeping every other one, or create the file. A configuration named dev, or on the same port, counts already. A file that isn’t a launch file, or isn’t JSON, is a warning that names it, and doctor doesn’t touch it: fix it, then run bb doctor --write again.

catalog: the saved catalog is stale

Warns. Why: .backbase/catalog.json was saved for another Backpack, or before a schema changed, such as Backpack is 4.12.0 now, and it was saved for 4.11.0. Commands that take --catalog refuse it.

Fix: Rebuild it, in the project’s folder: bb catalog --json --out .backbase/catalog.json --if-stale

More
  1. Rebuild it, in the project’s folder: bb catalog --json --out .backbase/catalog.json --if-stale
  2. Run bb doctor again

Doctor’s command adds --space-presets .backbase/space-presets.json when that file is there, and --space <id> when the catalog was saved with one. It gives the same fix when the file isn’t a catalog bb can read.

When it says .backbase/catalog.json wasn't compared with the project, such as with a storyblok.config that won’t load, bb can’t build the catalog either:

  1. Run bb catalog in the project’s folder, and fix what it says about the project’s files
  2. Run bb doctor again

The skills rebuild the catalog and the knowledge pack themselves before they use them, and tell you when they did.

project-slots: slot files not installed

Warns. Why: under --write, doctor installs the slot component compose leaves for a missing component, and something in the project stood in the way.

Fix: do what the warning names, then run bb doctor --write again.

More

It runs only with --write and --fix, after catalog. It writes src/components/BackbaseSlot/BackbaseSlotSB.tsx, backbase-slot.sb.ts, the map entry in component-list.ts and the slot’s places in backbase.placements.json, through the project’s Prettier, and leaves files that are there already. It warns when:

  • a slot file differs from bb’s: … differs from bb's slot component; kept the project's file. Check its export and schema name;
  • the project has more than one component-list.ts, or backbase-slot is already mapped to another component;
  • the files are written, but the project’s Prettier failed.

project-storyblok-token: sb-mig has no token

Fails. Why: STORYBLOK_OAUTH_TOKEN isn't in the environment or in the project's .env, so sb-mig can't reach Storyblok, or it’s in .env but empty. Doctor only looks for the name, never the value.

Fix: see Setting the Storyblok token.

Doctor’s steps
  1. In Storyblok, open My account, then Personal access token, and create one
  2. Put it in <project>/.env as this line: STORYBLOK_OAUTH_TOKEN=<your token>
  3. Or export it in your shell profile (~/.zshrc or ~/.bashrc): export STORYBLOK_OAUTH_TOKEN=<your token>, then open a new terminal
  4. Never paste the token into a chat with an agent: no agent needs to see it. Then run bb doctor again

Warns when your shell and the project’s .env set different tokens: STORYBLOK_OAUTH_TOKEN is set in your shell and in the project's .env, and they differ. The shell's overrides the project's .env: sb-mig uses the shell's, and so does bb doctor. Remove one. It compares them without showing either. bb doctor --write doesn’t count this warning: space-access checks the shell’s token.

  1. Keep the token in <project>/.env, and remove STORYBLOK_OAUTH_TOKEN from your shell profile (~/.zshrc or ~/.bashrc), then open a new terminal
  2. Or, if the shell’s token is the right one, remove the STORYBLOK_OAUTH_TOKEN line from <project>/.env
  3. Never paste either token into a chat with an agent. Then run bb doctor again

project-env-ignored: git could commit .env

Fails. Why: git doesn't ignore .env, or tracks it already, so the token could be committed. Without a .env, or outside git, it passes.

Fix: Add this line to <project>/.gitignore: .env

Doctor’s steps
  1. Add this line to <project>/.gitignore: .env
  2. If git tracks .env already, stop tracking it and keep the file: git rm --cached .env
  3. If a commit with .env was ever pushed, create a new Storyblok token and delete the old one

space-id: no Storyblok space id

Fails. Why: doctor says The project has no Storyblok space id, or that a value isn’t one, such as .backbase/config.json space.id must be a Storyblok space id, not "12a".

Fix: Add it to <project>/.backbase/config.json as space.id: { "space": { "id": "<space id>" } }

Doctor’s steps
  1. Add it to <project>/.backbase/config.json as space.id: { "space": { "id": "<space id>" } }
  2. Or set spaceId in storyblok.config
  3. Or pass it for one run: bb doctor --space <space id>
  4. Or set STORYBLOK_SPACE_ID in your shell or the project’s .env; find the id in the space’s settings in Storyblok

--space and the config files come first, and the shell wins over .env. With --space, doctor reads neither config file.

space-access: Storyblok refuses the token

Fails. Why: doctor asks Storyblok for the space, read-only, and it didn’t answer with the space. It’s skipped until space-id and project-storyblok-token pass.

Fix: Check the token is the personal access token of a Storyblok account with access to this space

More

Doctor asks the Management API sb-mig uses: storyblokApiUrl in storyblok.config, then NEXT_PUBLIC_STORYBLOK_MANAGEMENT_API_URL in your shell or the project’s .env, then the EU API.

When Storyblok refuses the token (401 or 403): the token is wrong or has expired, or its account has no access to that space.

  1. Check the token is the personal access token of a Storyblok account with access to this space
  2. If it isn’t, or has expired: in Storyblok, open My account, then Personal access token, and create one
  3. Put the new one in the project’s .env as STORYBLOK_OAUTH_TOKEN=<your token>, or export it in your shell profile. Never paste it into a chat with an agent

When Storyblok has no such space (404): the space id is wrong, or the space is in another region.

  1. Check the space id in the space’s settings in Storyblok
  2. If the space is in another region, set storyblokApiUrl in storyblok.config to that region’s Management API: EU https://mapi.storyblok.com/v1, US https://api-us.storyblok.com/v1, CA https://api-ca.storyblok.com/v1, AP https://api-ap.storyblok.com/v1, CN https://app.storyblokchina.cn/v1

When Storyblok doesn’t answer within 10 seconds, or can’t be reached:

  1. Check your network or VPN, then run bb doctor again
  2. If the space is in another region, set storyblokApiUrl in storyblok.config to that region’s Management API, as above

When Storyblok answered with an error, such as 500:

  • Storyblok may be busy or down: wait a minute, then run bb doctor again

When the Management API URL isn’t https, or isn’t a Storyblok Management API host, bb didn’t send the token: it sends it only over https to Storyblok’s own hosts (and to localhost or 127.0.0.1, for tests).

  • Set storyblokApiUrl in storyblok.config to your region’s Management API: EU https://mapi.storyblok.com/v1, US https://api-us.storyblok.com/v1, CA https://api-ca.storyblok.com/v1, AP https://api-ap.storyblok.com/v1, CN https://app.storyblokchina.cn/v1

When Storyblok answered, but not with a space:

  • Check that storyblokApiUrl in storyblok.config, or NEXT_PUBLIC_STORYBLOK_MANAGEMENT_API_URL, is a Storyblok Management API: EU https://mapi.storyblok.com/v1, US https://api-us.storyblok.com/v1, CA https://api-ca.storyblok.com/v1, AP https://api-ap.storyblok.com/v1, CN https://app.storyblokchina.cn/v1

When the token has spaces or line breaks in it, bb didn’t send it:

  1. Copy the token from Storyblok again, with nothing before or after it
  2. Put it on one line in the project’s .env as STORYBLOK_OAUTH_TOKEN=<your token>, or export it in your shell profile. Never paste it into a chat with an agent

When storyblok.config can’t be loaded, bb can’t tell which API sb-mig uses: doctor evaluates it in the project, as bb catalog does.

  • Fix storyblok.config so it loads, then run bb doctor again

project-translation-strategy: stories in locale folders

Warns for folder or an unsupported strategy; otherwise it passes. Why: with folder, the site asks for a locale path, so compose writes under the default locale’s root folder.

Fix: For a site without locale folders, set NEXT_PUBLIC_TRANSLATION_STRATEGY=none in the project’s .env

More

NEXT_PUBLIC_TRANSLATION_STRATEGY is read in Next’s order: shell, .env.local, then .env, defaulting to none. Doctor and compose share the reader. none and field use root stories. It’s advisory, under --write too.

For folder:

  1. Put stories and a settings story under each locale folder in Storyblok
  2. For a site without locale folders, set NEXT_PUBLIC_TRANSLATION_STRATEGY=none in the project’s .env

For an unsupported strategy, correct the source doctor names; a shell or .env.local value wins over .env. For .env:

  • Set NEXT_PUBLIC_TRANSLATION_STRATEGY in the project’s .env to none, field or folder, then run bb doctor again

space-settings-story: no settings story

Warns. Why: the boilerplate needs a story with slug and content type settings, and it’s missing, the wrong type, or can’t be checked.

Fix: In Storyblok, create a story with slug settings and content type settings at the root (settings)

More

It’s advisory, under --write too, and doctor never creates or publishes a settings story. Folder locales come from languageMap.locales in src/lib/i18n/languageMap.mjs.

For none or field:

  • In Storyblok, create a story with slug settings and content type settings at the root (settings)

For folder, create settings in each locale folder. For example, with locales en and de:

  • In Storyblok, create a story with slug settings and content type settings in the en locale folder (en/settings)
  • In Storyblok, create a story with slug settings and content type settings in the de locale folder (de/settings)

When a story at settings has another content type, doctor names it:

  • In Storyblok, use content type settings for the story at settings

When doctor can’t read the locale map or the stories:

  • Check the project’s translation strategy, locale map and Storyblok connection, then run bb doctor again

space-field-plugins: the space lacks a plugin

Warns. Why: a component uses a field plugin the space doesn’t have, so sb-mig would fail on it at Gate 2 with Storyblok’s 422. It never blocks a write: the rest of the sync, the theme included, still goes through.

Fix: Install <plugin> in the space (in Storyblok, through the plugin’s app or the organisation’s field plugins), then run bb doctor again

More

It warns only on positive evidence: the account’s or organisation’s list assigns the plugin to other spaces and not this one. For example: The space lacks field plugin description, so sb-mig would fail on sb-submit-button (field description, plugin description).

  • Install <plugin> in the space (in Storyblok, through the plugin’s app or the organisation’s field plugins), then run bb doctor again
  • Or leave the component out at Gate 2: bb space plan --exclude <component>. Add your reason as --exclude "<component>=<your reason>", and the plan lists it. The agent offers it when this check, or a sync, flags the component

A plugin it couldn’t verify isn’t a finding: it isn’t listed, is listed without its spaces, or the token can’t read the lists. bb then never suggests leaving a component out.

When it can’t read the project’s catalog, it can’t tell which plugins the components use:

  • Install the project’s dependencies (npm ci), then run bb doctor again

storyblok-mcp: Storyblok isn’t connected

Warns. Why: doctor finds no Storyblok plugin in Claude Code’s settings and no connected server in claude mcp list. A claude.ai connector shows in neither, so it only warns: check with /mcp.

Fix: In Claude Code, run /mcp and choose Storyblok to sign in

More

When there’s no Storyblok connection it can see, from Storyblok’s setup guide:

  1. Add Storyblok’s MCP server: claude mcp add --transport http --scope user Storyblok https://mcp.storyblok.com/mcp (or --scope project, for this project only)
  2. In Claude Code, run /mcp and choose Storyblok to sign in
  3. For Codex, Cursor and other clients, follow https://www.storyblok.com/docs/tooling/mcp-server/setup

When a Storyblok server is configured but not connected:

  1. In Claude Code, run /mcp and choose Storyblok to sign in, with your server’s name if it isn’t Storyblok
  2. Start a new Claude Code session, so it loads the connection

Setting the Storyblok token

When: project-storyblok-token fails, storyblok-token warns, or space-access says Storyblok refuses the token.

Why: sb-mig reads a Storyblok personal access token from STORYBLOK_OAUTH_TOKEN, in your shell or the project’s .env, and it isn’t in either, or doesn’t work.

Fix: put it in the project’s .env, the recommended place:

  1. In Storyblok, open My account, then Personal access token, and create one
  2. Put it in the project’s .env, in the project’s folder, as this line: STORYBLOK_OAUTH_TOKEN=<your token>. Or export it in your shell profile (~/.zshrc or ~/.bashrc): export STORYBLOK_OAUTH_TOKEN=<your token>, then open a new terminal
  3. Run bb doctor again in the project

A shell export overrides .env: with both set, sb-mig uses the shell’s, and project-storyblok-token warns if they differ. Never paste the token into a chat with an agent: none needs it, and none will ask. bb doctor only says whether it’s there and works, and project-env-ignored checks git won’t commit .env.

bb create

bb create runs its steps in order, and stops at the first that fails with its message and fix. /backbase:new shows you both, and stops too.

The folder isn’t empty

Why: the folder holds something already, and bb never overwrites a file.

Fix: pick another folder name, or empty the folder, then run it again.

More

/backbase:new stops before it creates anything and asks about the folder. bb create stops at Check the folder with <folder> isn't empty. bb create makes a new folder, or fills an empty one, and never overwrites. For a half-made project from a run that failed, see bb create stopped halfway.

Stopped at Check the machine

Why: right after the folder check, it runs the machine checks it needs, node and git, the same as bb doctor’s. Nothing is written yet.

Fix: follow the check’s steps, such as git’s, then run bb create again.

More

It shows the check’s id and detail, such as git: git isn't on PATH., then Fix: and the steps. --json lists every check in data.checks, and one that warns in data.warnings, without stopping.

bb create can’t reach the boilerplate

Why: neither SSH nor HTTPS gets into GitHub from this shell, and bb never stops to ask for a password or a passphrase.

Fix: gh auth login, then gh auth setup-git, and run bb create again.

More

It stops at Resolve the ref with Couldn't reach ef-global/storyblok-nextjs-backpack-boilerplate, and a reason for each. SSH has no key GitHub accepts (or ssh-agent doesn’t hold it), and HTTPS has no credential helper with access to ef-global. Set up either:

  • HTTPS, the quickest:

    gh auth login
    gh auth setup-git
  • SSH: add your key to GitHub and to ssh-agent, and check it with ssh -T git@github.com.

--transport https or --transport ssh uses only that one. bb create doesn’t need a gh sign-in first: git may clone with another credential helper, such as the macOS keychain. Only when HTTPS fails too does it run doctor’s github check, and give its fix.

It cloned over HTTPS, not SSH

Why: bb create tries SSH first and falls back to HTTPS when SSH doesn’t sign in, never waiting on a prompt. Resolve the ref says master is 1a2b3c4, over https (ssh: …).

Fix: nothing: the project is the same. For SSH next time, follow github-ssh.

More

bb doctor warned about it as github-ssh. --transport ssh makes bb create use only SSH, and fail when it can’t.

bb create stopped halfway

Why: a step after the clone failed, such as Install, and the failed run left a half-made project, so running it again says the folder isn’t empty. With --json, data.leftBehind is true.

Fix: do what the error says, then delete the folder and run bb create again.

More

Install errors include GH_PACKAGES_TOKEN isn't set, packages-token: GitHub Packages doesn't accept the token in GH_PACKAGES_TOKEN and npm ci failed. bb checks the GitHub Packages token only right before the install, once the clone’s .npmrc needs it; when GitHub Packages doesn’t answer in time, it warns and installs anyway. For the token, see packages-token; the install’s output is in .backbase/install.log. /backbase:new never deletes the folder for you. When only First commit failed, you don’t need to start again: see git has no identity.

git has no identity

Why: git needs a name and an email for the first commit, and bb create never makes one up. First commit fails with git has no complete user identity (a name and an email, for the author and the committer).

Fix: set yours, then make the first commit as the error shows it.

More

Everything before the commit worked. Use the short SHA the error gives:

git config --global user.name "Your Name"
git config --global user.email "you@ef.com"
cd my-site && git add -A && git commit --no-verify --no-gpg-sign -m "Start from storyblok-nextjs-backpack-boilerplate@<short sha>"

GIT_AUTHOR_NAME, GIT_AUTHOR_EMAIL, GIT_COMMITTER_NAME and GIT_COMMITTER_EMAIL work too. Then run /backbase:analyze <figma link> --project my-site to carry on.

The first commit isn’t signed

Why: bb create commits with --no-gpg-sign, because signing would ask for a passphrase an agent would wait on forever. Its step reads “unsigned first commit”.

Fix: sign it yourself, in the project: git commit --amend --no-edit -S

npm and Figma

npm returns 401 for @ef-global

Why: npm reaches GitHub Packages but can’t sign in: the token is missing, expired or lacks read:packages, or GH_PACKAGES_TOKEN isn’t set in the shell that runs npm.

Fix: check ~/.npmrc has both lines from step 4 of Getting started.

More

It fails with E401 or 401 Unauthorized, from npm install or npx -y @ef-global/backbase.

  1. Check that ~/.npmrc has both lines from step 4 of Getting started.
  2. Make sure the token is a classic token with read:packages, and that it hasn’t expired. If your organisation uses single sign-on, authorise the token for ef-global on GitHub.
  3. If the project’s .npmrc uses ${GH_PACKAGES_TOKEN}, export it and check it’s there: echo "${GH_PACKAGES_TOKEN:+set}" prints set when it has a value. Restart Claude Code from that shell.

A 404 Not Found instead usually means the @ef-global:registry line is missing, so npm looks on the public registry.

Desktop app Figma sign-in fails

Why: the desktop app’s sign-in for remote MCP servers is less reliable than the terminal’s: the browser opens, but the sign-in never completes.

Fix: sign in from a terminal, claude mcp login figma, then start a new session.

The Figma MCP isn’t connected

Why: it was never added, was added for one project only, or isn’t signed in. Claude Code loads MCP servers only when a session starts.

Fix: claude mcp list, and add or sign in to figma if it isn’t there.

More

/backbase:analyze, or /backbase:new after it made the project, stops at the analyse flow’s first checks. Add it for your user, and sign in:

claude mcp add --transport http --scope user figma https://mcp.figma.com/mcp
claude mcp login figma

Then start a new session and run /backbase:analyze again. When /backbase:new already made the project, run /backbase:analyze <figma link> --project <folder>.

Very tall frames

Why: a tall frame has more layers than one Figma response can hold: reading stalls, a response is cut off, or the session runs out of room.

Fix: link a smaller frame, a group of sections rather than the whole page.

More

The agent is built for this: it takes the outline from a small script instead of get_metadata, which fails on very large frames, screenshots a tall frame part by part, and reads three parts a call, halving the batch when one overflows. You can also split the page into a few frames in Figma and analyse each in its own session.

bb isn’t found, or is Babashka

Why: bb doesn’t need to be installed globally, and a bb on your path may be Babashka, an unrelated Clojure tool. You see bb: command not found, or a babashka version.

Fix: run Backbase’s through npx: npx -y @ef-global/backbase --version

More

The plugin runs the project’s own bb from node_modules/.bin, or else npx -y @ef-global/backbase@<version>, pinned to its release. To have the agent use the project’s:

npm install --save-dev @ef-global/backbase
npx bb --version

You don’t need to uninstall Babashka. If the agent runs plain bb and gets Babashka, tell it to use npx -y @ef-global/backbase.

The plan and the space

Not a Backpack project

Why: there’s no node_modules/@ef-global/backpack: the dependencies aren’t installed, Claude Code started in another folder, or the project doesn’t use Backpack 4.

Fix: npm install in the project (it needs the GitHub Packages setup).

More

Start Claude Code in the project’s root folder, or pass --project <dir>. To start without a project, run /backbase:new <figma link> <folder>: see Start from scratch.

A command says catalog-stale

Why: the catalog was saved at analyse time, and Backpack or a schema changed since. bb never uses a catalog for another Backpack.

Fix: run the command the message ends with, such as bb catalog --json --out .backbase/catalog.json --if-stale, then yours again.

More

It reads .backbase/catalog.json was saved for Backpack 4.11.0, and the project has 4.12.0, or was saved before these changed: and the schema files. Rebuild the knowledge pack too, with bb catalog --knowledge --out .backbase/knowledge.md --if-stale and the flags it was compiled with. The skills do both themselves.

Bloks missing from the component map

Why: component-list.ts has no entry for some bloks, so each renders nothing where the page hands it to the map. bb catalog lists a missing-map-entry for each.

Fix: register the ones that reach the map in component-list.ts, and list the rest in component-map.exceptions.json with a reason.

More

That’s often fine: some bloks never reach the map, because their parent renders them or reads them as data. List those at the project’s root:

{
  "sb-link-card": "CardSB reads the link off `action` as data",
  "sb-form-select-option": "FormSelectSB reads `options` as data"
}

bb catalog then excuses them. The boilerplate’s npm run check:map reads the same file, and so does the Chaperone preset’s schema-is-registered rule, which needs it to exist: bb doctor --write creates it as {}.

Every component fails schema-name-matches-folder

Why: .chaperone.json pins a Chaperone older than 0.12.0, which ignores the preset’s case transform, so no folder ever matches. You see Put <kebab>.sb.ts in src/components/<PascalCase>/, and maybe warnings about unknown options such as transform.

Fix: npx @ef-global/backbase doctor --write

More

It raises chaperoneVersion to 0.12.0, keeping a newer pin, and Chaperone downloads that version on its next run. An older Chaperone also ignores the map exceptions and the command rules’ per-component results. bb doctor’s project-chaperone names the old pin.

A component failed at Gate 2

Why: sb-mig couldn’t write that component. The others were written, and so was the theme, which never waits on components.

Fix: let /backbase:sync plan again without it: bb space plan --exclude "<component>=<your reason>".

More

bb space sync fails with component-failed: sb-mig couldn't write component <name>; the other components were synced. Fix it and plan again, or leave it out: bb space plan --exclude <name>, with sb-mig’s words under it. When the space lacks a field plugin (Storyblok’s 422), it reads Storyblok says the space lacks field plugin <plugin>, which <name> needs: install it in the space, or leave <name> out, and .backbase/space-sync.json lists it under fieldPluginFailures.

/backbase:sync offers the ways round it, and does neither without your yes:

  1. For a missing field plugin, install it in the space, then plan and sync again. Doctor’s space-field-plugins names it before a sync when it can tell
  2. Or leave the component out with --exclude, and take the new plan to Gate 2. A plan made again without it plans the component again, and fails on it again

component-not-synced means sb-mig’s report lacks a component the sync named, so it wasn’t written. sb-mig finds a component by its schema file’s name: check each has one .sb file named after it (not one in the project and another in node_modules), then plan again.

Gate 2 skipped the theme

Why: bb writes the theme only as planned, and someone changed a token or saved the Settings story since the plan, or the sync wrote a datasource the theme was planned from.

Fix: close Settings in Storyblok, run /backbase:sync again, and approve the new plan.

More

bb space sync fails with theme-plan-again: 1 theme write wasn't made, as the space changed since the plan. Run bb space plan --sections again and take the new plan to Gate 2., then each write it skipped. Or the sync went through, and the old theme came back once someone saved Settings: Storyblok has no conditional write, so a Settings tab opened before the sync holds the old theme, and saving it brings it back.

  1. Close the Settings story in Storyblok before the sync, and reopen it after
  2. Run /backbase:sync again, so it plans the theme again, and approve the new plan at Gate 2: it needs its own yes
  3. bb saves the Settings story as a draft and never publishes it: publish it when you’re happy

The page

The page didn’t settle

Why: bb measures a page only once it has loaded and holds still, and something kept loading or moving for 20 seconds. You see page-not-settled, and what was still busy.

Fix: reload the page in your browser, then run the command again.

More

The error names it, such as Hero (9:1)'s height went from 480px to 612px, 2 images weren't decoded, the network wasn't idle: 1 request still loading (/api/prices) or the page reloaded while settling. The skills wait and try once more, then tell you. Then:

  • A dev server compiling the page on first visit can take longer than 20 seconds: reload it, then run the command again.
  • A slow page: give it longer with --settle-timeout 60000.
  • A section that keeps moving, or an image that never loads, such as an autoplaying carousel whose slides differ in height: look at that section on the page.
  • The page reloaded: the dev server reloaded it, often because a file changed. Run it again once it’s quiet.
  • The network is never idle: something starts a request less than half a second after the last ended, such as analytics or a chat widget. Turn it off in development. A poll every few seconds is fine.

--allow-unsettled measures anyway, marked settled: false, and nothing is judged from it: use it to look, not to refine. See Waiting for the page to settle.

A section wasn’t reviewed

Why: the review captures a section only once it has settled in view, and never crops a half-loaded one. bb page review lists it as not-captured, with a reason.

Fix: run it again for that section: bb page review … --section <key>.

More
  • It didn't settle in view:, or it moved while it was captured: run it again with --section <key>, the key from index.json. A section that never holds still in view, such as a carousel whose slides differ in height, needs its motion turned off in development; --settle-timeout 60000 helps one that’s just slow.
  • None of its bloks … has an element with a box on the page: the page doesn’t render the story with data-blok-uid. Render it through bb story serve, or the preview route with --draft.
  • No Figma shot for it: the read skill didn’t save <node id>.png in shots/ beside sections.json. Read the frame again, or pass --shots <dir>.
  • The review ran out of its 180s (--review-timeout): review the rest with --section <key>, or give it longer with --review-timeout 300000.

A sticky bar shows only once

Why: that’s on purpose. The review captures a tall section a viewport at a time, so bb pins a bar that’s sticky inside the section where the flow puts it, rather than at the top of every slice.

Fix: nothing. Compare the bar with where the frame draws it.

More

A booking bar or a section’s own nav shows once, at the top of the section. While it captures, bb sets it position: relative, which moves nothing, and puts it back after. What’s fixed or sticky outside the section, such as the site’s header, is hidden. When Figma shows the bar stuck lower down, that’s a layout item for the review, not a capture problem.

Grid or flex collapses when shown

Why: a local wrapper calls Backpack’s getVisibilityClasses without originalDisplayProperty, so Show adds block and the root’s grid or flex is gone. Wrappers that bb component new 0.18 or earlier wrote do this.

Fix: bb check components --visibility, then let /backbase:component fix each wrapper it names.

More

Its stack, grid or row collapses into a block once its visibility is Show, as FanStack’s did in the ILS run: Backpack’s cn keeps the last display class. /backbase:component makes the change only after you say yes. To do it yourself, pass the display it names, such as originalDisplayProperty: 'grid', and name the classes in the file (grid md:grid lg:grid xl:grid xxl:grid) so Tailwind builds them. The preset’s wrapper-visibility-keeps-display rule runs the same check.

A dashed box, not a component

Why: it’s a backbase-slot, reserving a planned Wrap or Create. That’s expected in dev and drafts, and it renders nothing in published production content.

Fix: run /backbase:component to build it.

More

bb story slots --json shows its name, Figma node and kind. Refine skips its geometry. If the slot files are missing, run bb doctor --write and review its installation check.