Troubleshooting
Common issues and solutions when working with the Forge CLI.
First step: run diagnostics
Before diving into specific errors, run:
forge doctor
forge doctor --network # after forge login + forge app select
forge doctor checks Node, CLI config, authentication, git/GitHub CLI, Docker, and the extensibility monorepo checkout. Add --strict to fail on warnings (useful in CI). Filter with --check <id> or --skip <id> — see Command Reference for check ids.
Authentication
Session Expired or Invalid
Symptom: Commands fail with "session expired" or "not authenticated" errors.
Solution: Re-authenticate:
forge login
The CLI automatically detects expired sessions and clears stale credentials. You do not need --force, as running forge login is sufficient.
"Mandatory fields are missing" or 400 Bad Request
Symptom: A command fails with a generic 400 Bad Request: Mandatory fields are missing error rather than the usual "session expired" message.
Explanation: Your session has expired after a period of inactivity, but the expiry surfaced as a generic 400 instead of a clear "session expired" message. The CLI keeps your session alive automatically while you're actively running commands; stepping away for an extended period can still let it expire.
Solution: Force a fresh login:
forge login --force # re-authenticate even if the CLI thinks you're logged in
GitHub CLI Token Expired
Symptom: forge widget submit or PR commands fail with "GitHub CLI token is expired or invalid."
Solution: Re-authenticate with the GitHub CLI:
gh auth login
gh auth status # verify
The CLI pre-checks GitHub authentication prior to submission. If the token has expired, it throws an explicit error with guidance.
Widget Development
"Not Inside a cdx-extensibility-apps Project"
Symptom: forge widget create, forge widget preview, or forge widget build fails with this error.
Explanation: The CLI resolves the extensibility apps project in this order:
- Environment variable —
export FORGE_EXTENSIBILITY_APPS=/path/to/cdx-extensibility-apps - Current directory —
cdinto any directory inside a clone - Stored config — set automatically after the first auto-setup
- Auto-cache —
~/.forge/cdx-extensibility-apps(cloned automatically on first use)
Any widget or playground command auto-clones the public template to ~/.forge/cdx-extensibility-apps on first use if no checkout is found.
Widget Name Mismatch ("-widget" Suffix)
Symptom: You create a widget named spend-chart but the CLI shows it as spend-chart-widget in the preview picker.
Explanation: The Nx generator appends a -widget suffix to the project name. The CLI handles this automatically — you can use either spend-chart or spend-chart-widget in commands and the CLI resolves the correct project.
Mobile Preview: Web Bundling Failed
Symptom: forge widget preview <name> --platform mobile fails with Web Bundling failed...Unable to resolve "react-native-web".
Explanation: This happens when Expo attempts web bundling in the mobile sandbox. The CLI sets EXPO_NO_WEB=1 to suppress this, but if you see the error:
- Ensure you are running the latest version of the Forge CLI (
brew upgrade forge-cliorpnpm update -g @cdx-forge/cli) - Verify that
~/.forge/cdx-extensibility-apps/playground/mobile-sandbox/app.jsondoes not contain a"web"configuration section
Mobile Preview: QR Code Not Scanning
Symptom: Scanning the Expo QR code with the iPhone Camera app shows "no usable data found."
Solution: The iPhone Camera app does not handle exp:// URLs. Use the Expo Go app's built-in QR scanner instead:
- Install Expo Go from the App Store / Play Store
- Open Expo Go and tap the QR scanner
- Scan the QR code displayed in the terminal
Alternatively, press i in the terminal to open an iOS Simulator, or a for an Android emulator.
Mobile Preview: Expo Go "Opening Project..." Hangs
Symptom: Expo Go opens but stays stuck on "Opening project..." and never loads.
Cause: Your phone cannot reach Metro Bundler's local IP address. The phone and dev machine must be on the same Wi-Fi network, or you must use Expo's tunnel mode.
Solutions:
# Option 1: Connect your phone to the same Wi-Fi as your dev machine
# Option 2: Use tunnel mode (works across any network, including cellular)
cd ~/.forge/cdx-extensibility-apps/playground/mobile-sandbox
npx expo start --tunnel --port 8083
# Option 3: Use a simulator instead (no network needed)
# Press 'i' in the Metro terminal for iOS Simulator
# Press 'a' for Android emulator
Mobile Preview: Metro Bundler "Unable to Resolve Module"
Symptom: Metro fails with Unable to resolve module ... after adding a new widget or dependency.
Cause: Metro's cache is stale.
Solution: Clear caches and restart:
cd ~/.forge/cdx-extensibility-apps # or your project root
npx expo start --clear
If the error references your widget package name, run npm install at the project root to re-link the workspace package.
Web Preview: Browser Opens to Blank Page
Symptom: forge widget preview opens the browser but the widget slot is empty or the page does not load.
Solution: The CLI pre-checks that the OLB playground and the widget's remoteEntry.js are reachable before opening the browser. If you still see a blank page:
- Check that the OLB Docker playground is running:
docker ps | grep olb-playground - Check that the dev server is running: verify the Nx terminal output for build errors
- Reload the page — some Aspects register after the initial page load
Aspect Development
Banner or Aspect Not Appearing After Preview
Symptom: forge aspect preview opens the browser but the Aspect does not display.
Solutions:
- Reload the page — the OLB shell runs injected Aspects on load. Navigate to
http://localhost:4200and reload. - Check for syntax errors — if the generated JavaScript has a syntax error, the Aspect silently fails. Check the saved file under
./aspects/or check the browser console for errors. - Multiline message issue — see the next section.
Multiline Message Not Working
Symptom: The --message flag with \n shows a literal backslash-n instead of a newline.
Solution: Use ANSI-C quoting ($'...') so escape sequences are interpreted:
# Correct — $'...' interprets \n as a newline
forge aspect preview --template banner --message $'Headline\nSubline'
# Wrong — plain quotes pass literal \n
forge aspect preview --template banner --message 'Headline\nSubline'
Context-Aware Template Shows "Valued Customer"
Symptom: Templates like welcome-banner or personalized-toast show fallback text instead of the user's name.
Explanation: Context-aware templates use dbk.sessionInfo() which is only available in the OLB playground environment. If you are using --no-playground (local mock), the session context is unavailable and the template falls back to generic text.
Solution: Run without --no-playground to get live personalized data:
forge aspect preview --template welcome-banner --message 'Check out our new rates!'
Vendor presets or mock partner URLs fail
Symptom: forge aspect preview with --template vendor-script-loader (or another vendor-oriented template) and --preset <id> loads, but the browser console shows script errors or 404 for SDK URLs.
Solutions:
-
Run a mock partner server on the host and port your preset expects (defaults often use
http://localhost:4011). Presets ship with stub URLs only — they are not live vendor endpoints. -
Point the CLI at your mock server if it is not on the default port: set
MOCK_PARTNERS_URLorMOCK_PARTNERS_PORTso auto-discovery finds it before preview. -
Inspect generated code without opening a browser:
Bashforge aspect templates --id vendor-script-loader --preset engagement-script-loader --preview-code
OLB Docker Playground
"docker-compose.yml Not Found"
Symptom: The CLI cannot find the Docker Compose file.
Explanation: This file comes from cdx-extensibility-apps/playground/web/. The auto-setup should handle this; if it persists, set the environment variable:
export FORGE_EXTENSIBILITY_APPS=/path/to/cdx-extensibility-apps
Port 4200 Already in Use
Solution: Stop other containers or processes using that port, then retry:
docker ps # find the conflicting container
docker stop <container-id> # stop it
forge playground up
Docker Pull Unauthorized
Symptom: docker pull or forge playground up --pull fails with unauthorized from ghcr.io.
Solution: Authenticate Docker with a GitHub Personal Access Token (classic scope read:packages, or fine-grained with Packages: Read):
echo YOUR_GITHUB_PAT | docker login ghcr.io -u YOUR_GITHUB_USERNAME --password-stdin
Then retry: forge playground up --pull
Submission
Widget Submission: Repository Not Found
Symptom: forge widget submit fails with "Could not resolve to a Repository."
Explanation: This usually means the FI repository has not been created yet or the name does not match:
- Check repository status:
forge repo status - If no repository exists, create one:
forge repo init - Verify you have been added as a collaborator — check your email for a GitHub invitation
If the error persists after confirming repository access, the CLI displays the repository name it is trying to access so you can verify it with your administrator.
Localhost URLs in Submission
Symptom: The CLI warns about localhost URLs during forge widget submit.
Explanation: This is expected. If you developed with the mock API server, your widget contains localhost URLs that will not work in production. The CLI detects these and prompts you to provide production URLs before the PR is created.
To skip the prompt and inject a target-environment URL automatically, pass --source-url:
forge widget submit my-portfolio --source-url https://api.acmebank.com
Pre-Submit Lint Checks Failing
Symptom: forge widget submit aborts with ESLint, TypeScript, or markdownlint errors before creating the PR.
Explanation: By default, widget submit runs ESLint, TypeScript type-check, and markdownlint to keep PRs clean. Common fixes:
no-console— replaceconsole.logwith proper logging or remove debug statements.- TypeScript errors — run
npx tsc --noEmitlocally and fix surfaced types. - Markdown — make sure
README.mdhas no trailing spaces, uses consistent heading levels, and has a blank line before/after fenced code blocks.
To bypass the checks (for example, while debugging metadata issues):
forge widget submit my-portfolio --no-lint
Submission CI Failure: "tsup: not found" or "Cannot find module 'typescript'"
Symptom: A widget PR's CI fails with tsup: not found or Cannot find module 'typescript', especially for mobile widgets.
Explanation: Mobile widget builds use tsup, which lives in the widget's devDependencies. The CLI automatically adds tsup and typescript to the FI repo's root devDependencies and updates the lockfile during submission. If CI still fails:
-
The lockfile may not have been updated — re-submit the widget (the CLI now runs
npm installduring submission to sync the lockfile). -
If the CI uses a strict
npm ciand the lockfile is out of sync, push a manual lockfile update:Bashgh repo clone <org>/<repo> /tmp/fix -- --branch <branch>
cd /tmp/fix && npm install --package-lock-only
git add package-lock.json && git commit -m "fix: update lockfile" && git push
Submission CI Failure: "Cannot find module 'stage-nx-package.js'"
Symptom: A widget submission's CI fails referencing stage-nx-package.js.
Explanation: That script only exists in the cdx-extensibility-apps monorepo. The CLI strips its reference from the widget's project.json during submission. Older submissions made before this fix may still carry the reference.
Solution: Re-submit the widget with the latest CLI version, or manually remove the script reference from the widget's project.json and push a fix-up commit to the PR.
Updating an Existing Widget PR
If you need to push additional commits to an open submission PR (e.g., to address review feedback), use --update:
forge widget submit my-portfolio -u
# or: forge widget submit my-portfolio --update
To force a brand-new PR even if one is already open for the widget:
forge widget submit my-portfolio --new