Troubleshooting
Common issues and solutions when working with the Forge CLI. Start with diagnostics, then jump to the section that matches the error.
| If you see | Go to |
|---|---|
forge doctor fails or looks stuck | First step: run diagnostics |
| Session expired, 400 Bad Request, or login does not stick | Authentication and app selection |
Checkout missing, invalid layout, or forge widget init | Extensibility-apps checkout |
nx not available, slow or hung npm install, blocked npmjs | npm, Nx, and Windows |
| Preview never opens, blank playground, Docker errors | Web preview and the OLB playground |
| Mobile preview, Metro, Expo Go, or QR code | Mobile preview |
Aspect not visible, \n, or vendor preset 404 | Aspect development |
| Submit, lockfile, or CI failures | Submission |
First step: run diagnostics
forge doctor --verbose
forge doctor --network --verbose # after forge login and forge app select
forge doctor checks runtime (Node, CLI), auth, git/GitHub CLI, Docker, the extensibility-apps checkout, Nx, and mobile tooling. Mobile checks warn only. Without --strict, those warnings do not fail the run.
--network probes BFF reachability and API token exchange (login required; token exchange also needs forge app select). It does not test npm, GitHub, GHCR, or Expo. Those need the checks in the sections below.
Useful flags (see Command Reference for check ids):
| Flag | What it does |
|---|---|
--verbose / -v | Include versions, resolved paths, and extra data fields. Use this when you file a support ticket. |
--timeout <ms> | Per-check timeout. Default is 8000 ms. On a slow Windows machine, the Nx probe can time out and doctor warns nx not available in extensibility-apps checkout even when a later npx nx --version works. Re-run with --timeout 60000 before you treat Nx as broken. |
--check <id> | Run only named checks (repeatable). |
--skip <id> | Skip named checks (repeatable). |
--json | Machine-readable report for scripts and CI. |
--strict | Treat warnings as failures (exit 1). Useful in CI. |
--no-color | Disable ANSI colors (also honors NO_COLOR). |
Exit codes: 0 when there are no failures (warnings and skips are allowed). 1 when any check fails, when --strict sees a warning, or when --check names an unknown id.
Focused checkout and Nx re-check:
forge doctor --verbose --timeout 60000 --check ext.root --check ext.rootValid --check nx.invocation
Refresh runs only when doctor resolved the managed cache at ~/.forge/cdx-extensibility-apps. If you are already inside another valid checkout, that path wins and the cache is not refreshed. When the cache is the resolved root and the refresh marker is older than about five minutes, the CLI runs git fetch --quiet origin. If local HEAD and origin/HEAD differ, it then runs git checkout -- ., git pull --ff-only, and npm install. That is why doctor sometimes sits on Installing dependencies (npm install).... Let it finish. Interrupting mid-install is a common cause of later Nx warnings.
A refresh can revert tracked files in the checkout. Generated widget folders under widgets/ are usually untracked and kept. Registry and workspace wiring in tracked files can disappear. If a widget you already created no longer previews after doctor, see Checkout refresh reverted my widget wiring.
Authentication and app selection
Session expired or invalid
Symptom: Commands fail with "session expired" or "not authenticated."
Solution: Force a fresh login:
forge login --force
forge status
If the CLI can still verify the session with the server, plain forge login prints that you are already logged in and tells you to pass --force. Use --force whenever a command fails with an auth error. The idle window is about 30 minutes. Doctor's auth.sessionExpiry check reports the same and recommends forge login --force.
Login succeeds, next command says you are not logged in
Symptom: forge login succeeds, then the next command reports "Not logged in." You may also see OS credential store unavailable — credentials will not persist between commands.
Cause: The OS keyring could not load, so credentials live only for that process.
Solution:
- macOS: reinstall Forge for your CPU architecture (arm64 vs x64):
brew reinstall forge-cli - Linux: install libsecret, for example
sudo apt-get install libsecret-1-0
"Mandatory fields are missing" or 400 Bad Request
Symptom: A command fails with 400 Bad Request: Mandatory fields are missing instead of "session expired."
Explanation: A generic 400 can show up after you have been idle, or when a request is missing fields. The CLI retries once only when the body looks like a session expiry. If forge login --force does not clear it, the 400 is a different API error.
Solution:
forge login --force
forge status
GitHub CLI token expired
Symptom: forge widget submit fails with "GitHub CLI token is expired or invalid."
Solution:
gh auth login -h github.com
gh auth status
forge widget submit pre-checks GitHub authentication before it opens a PR. forge aspect submit does not run that pre-check.
App select and skipped network checks
Symptom: forge doctor --network shows SKIP for token exchange: no app with API keys selected (run forge app select). Or forge app select errors with a missing BFF app title or no keys.
Explanation: SKIP is not a pass. Token exchange needs a selected app with API keys. The BFF reachability check only needs login.
Solution:
forge app list
forge app select
forge status
forge doctor --network --verbose
If select says the app is missing a BFF app title, re-create the app in the Developer Console. If it says no keys were found, generate API keys in the Developer Console, then run forge app select again.
If an old Production session has no tier, run forge login (the CLI may already have cleared those credentials). If doctor still fails auth.environmentAvailable, use forge logout && forge login.
Extensibility-apps checkout
Widget create, preview, build, and the OLB playground use a local clone of cdx-extensibility-apps. On first use the CLI clones it to the managed cache and runs npm install there. That first install can take several minutes.
Default location:
- macOS / Linux:
~/.forge/cdx-extensibility-apps - Windows:
%USERPROFILE%\.forge\cdx-extensibility-apps(Command Prompt) or$env:USERPROFILE\.forge\cdx-extensibility-apps(PowerShell)
Confirm the path doctor actually resolved:
forge doctor --verbose --check ext.root --check ext.rootValid
Look at ext.root. Do not assume a different folder.
A valid checkout has nx.json plus either playground/web/docker-compose.yml or a widgets/web / widgets/mobile folder. Fresh clones ship the playground compose file before the first forge widget create creates widgets/.
Checkout not found or invalid
Symptom: Doctor warns ext.root is not configured (not configured). If no root is resolved, ext.rootValid is skipped, not failed. Widget create (except --local), preview, and init auto-clone a missing cache. If the cache directory exists but is not a valid checkout, the CLI first tries git checkout -- . and git pull --ff-only inside it. If it is still invalid, they throw {path} exists but is not a valid cdx-extensibility-apps checkout.
Solution: Recreate the managed checkout. Do not delete it in place if it already contains widgets. Move it aside, then bootstrap:
# macOS / Linux
mv ~/.forge/cdx-extensibility-apps ~/.forge/cdx-extensibility-apps.bak
forge widget init
# Windows PowerShell
Move-Item "$env:USERPROFILE\.forge\cdx-extensibility-apps" "$env:USERPROFILE\.forge\cdx-extensibility-apps.bak"
forge widget init
REM Windows Command Prompt
move "%USERPROFILE%\.forge\cdx-extensibility-apps" "%USERPROFILE%\.forge\cdx-extensibility-apps.bak"
forge widget init
forge widget init is the bootstrap command for this cache. It does not appear in forge --help. forge widget preview and forge widget create (without --local) also clone the cache on first use if it is missing. forge widget create --local writes files only and does not clone.
Copy your widget folders back from the .bak tree (widgets/web and widgets/mobile) after init finishes. Then reinstall dependencies in the new checkout. See Reinstall dependencies.
Checkout refresh reverted my widget wiring
Symptom: Widget source is still under widgets/, but preview cannot find the widget, or mobile preview says the widget id is not in WIDGET_REGISTRY.ts.
Cause: A managed-cache refresh reset tracked files (registry, package.json workspace entries) while leaving untracked widget source.
Solution: Re-scaffold is not required if the source is intact. Prefer forge widget preview or forge widget build against the existing folder. If the registry row is gone, add it back from the mobile-sandbox README, or copy the registry file from your .bak checkout if you moved one aside.
Do not retry forge widget create on a name that already exists. The CLI throws Widget "…" already exists at …. It does not overlay or replace src/ on retry. After Nx generates a new widget, the CLI overlays template files only when the template is not sdk-demo.
npm, Nx, and Windows
Doctor warns nx not available in extensibility-apps checkout (fix cd <root> && npm install) when it cannot run Nx from the checkout. That is a warning, not a failure, unless you pass --strict. Widget commands still throw Nx is not available in this project. From the extensibility-apps directory run: npm install.
Nx is a local workspace tool. You do not need a global nx install. Doctor and widget commands try, in order: the checkout's local nx bin, then npx nx, then pnpm exec nx.
Before you declare Nx missing, raise the doctor timeout:
forge doctor --verbose --timeout 60000 --check nx.invocation
If the pass message says npx nx or pnpm exec nx instead of nx, the local node_modules/nx bin is missing or broken. Reinstall dependencies.
Reinstall dependencies
Work in the managed checkout root. Keep package-lock.json. Do not delete it.
# macOS / Linux
cd ~/.forge/cdx-extensibility-apps
node -v
npm -v
npm config get registry
npm ping
npm install --timing --loglevel=verbose
npx nx --version
# Windows PowerShell
cd $env:USERPROFILE\.forge\cdx-extensibility-apps
node -v
npm -v
npm config get registry
npm ping
npm install --timing --loglevel=verbose
npx nx --version
REM Windows Command Prompt
cd /d "%USERPROFILE%\.forge\cdx-extensibility-apps"
node -v
npm -v
npm config get registry
npm ping
npm install --timing --loglevel=verbose
npx nx --version
The CLI requires Node.js 18+. The extensibility-apps checkout README asks for npm 9+ (some Node 18 builds ship an older npm). Run npm install from the checkout root, not from a widget subdirectory.
--timing --loglevel=verbose prints progress. The idealTree and cache-scan phases can look idle. That is normal for several minutes on a first Windows install. If verbose output has not printed a new line for a long stretch (for example 10+ minutes with no HTTP activity), treat it as stuck. Capture the log instead of waiting indefinitely.
Do not interrupt a healthy install. Stopping mid-extract is a common cause of "package present, dependency missing" trees and repeated Nx errors.
When npx nx --version prints a version, re-run:
forge doctor --verbose --timeout 60000 --check nx.invocation --check ext.rootValid
Then retry the original widget command (forge widget preview or forge widget create), not a second create of the same name.
npm errors
Match the log, then fix that class:
| Error | Likely cause | What to do |
|---|---|---|
ENOTFOUND, EAI_AGAIN | DNS or blocked host | Confirm npm config get registry is https://registry.npmjs.org/. Ask IT to allowlist registry.npmjs.org. |
ETIMEDOUT, ECONNRESET, socket hang up | Firewall, proxy, or VPN | Connect to the corporate VPN if required. Ask IT to allow HTTPS to the registry. |
E401, E403, 401 / 403 | Registry auth | You are hitting a registry that requires credentials, or a proxy is intercepting npm. See Corporate network and registry access. |
UNABLE_TO_GET_ISSUER_CERT, CERT_HAS_EXPIRED, self signed certificate | TLS inspection | Trust the corporate CA with NODE_EXTRA_CA_CERTS pointing at a PEM bundle from IT. Do not set strict-ssl=false. |
ENAMETOOLONG | Windows path length | Enable Win32 long paths (LongPathsEnabled) and git config --system core.longpaths true. Keep the checkout under the default .forge path. |
EPERM, file locked, EBUSY | Antivirus or indexer | See Windows VDI and endpoint scanning. |
When npm fails, it prints a path under the npm cache _logs directory. Attach that file when you escalate.
Clean node_modules (only after you have logs)
If npx nx --version still fails after a completed npm install, and you already saved the verbose log:
# macOS / Linux
cd ~/.forge/cdx-extensibility-apps
rm -rf node_modules
npm install --timing --loglevel=verbose
npx nx --version
# Windows PowerShell
cd $env:USERPROFILE\.forge\cdx-extensibility-apps
Remove-Item -Recurse -Force node_modules
npm install --timing --loglevel=verbose
npx nx --version
REM Windows Command Prompt
cd /d "%USERPROFILE%\.forge\cdx-extensibility-apps"
if exist node_modules rmdir /s /q node_modules
npm install --timing --loglevel=verbose
npx nx --version
Leave package-lock.json in place. A full reinstall re-resolves the workspace (web React 18 and mobile React 19 in one tree). Use it as an escalation step, not the first fix.
Windows VDI and endpoint scanning
On managed Windows, real-time scanning of tens of thousands of small files under node_modules makes npm install look hung.
Ask IT for path exclusions (do not turn scanning off yourself):
- The checkout:
%USERPROFILE%\.forge\cdx-extensibility-apps node_modulesinside that checkout- The npm cache:
%LOCALAPPDATA%\npm-cache
If IT cannot exclude Defender or a third-party agent (CrowdStrike, Carbon Black, Symantec, and similar), expect first installs to take much longer. Keep verbose logs running so you can tell a slow scan from a blocked registry.
Windows also needs long-path support for the React Native tree. If install fails with ENAMETOOLONG, have IT enable long paths before you wipe node_modules again.
Corporate network and registry access
Local widget create and preview need outbound HTTPS to:
registry.npmjs.org(npm install of the checkout)- GitHub (
github.com) for the template clone ghcr.iofor OLB playground images only (web preview /forge playground up --pull). Widget create and mobile preview do not pull GHCR.
forge doctor --network does not prove any of those. Use npm ping, git ls-remote https://github.com/candescent-dev/cdx-extensibility-apps.git, and the Docker pull error text.
Default. Point npm at public npm:
npm config get registry
npm ping
You want https://registry.npmjs.org/ and a successful PING/PONG. If the host is blocked, ask IT to allowlist registry.npmjs.org. There is no Candescent-hosted npm registry for customers.
Your own registry. If your institution already runs an npm-compatible registry that mirrors public packages, you can use it for the local checkout install:
cd ~/.forge/cdx-extensibility-apps
npm install --registry=https://npm.example.bank.internal --timing --loglevel=verbose
Prefer a one-off --registry flag (or a checkout-local .npmrc) over npm config set registry, which writes your user-level ~/.npmrc.
forge widget submit does not copy the apps-checkout package-lock.json or .npmrc. Web submit copies the widget project (minus node_modules, .nx, and dist). Mobile submit generates the project in the FI repo, overlays src/, and merges missing devDependencies, peerDependencies, and the build/dev scripts. It does not merge ordinary dependencies.
Submit does run npm install in a temp clone of the FI promotions repo on your machine. That install honors user/global npm config (~/.npmrc), not the checkout .npmrc. If you permanently change the user-level registry, the FI package-lock.json can record private resolved URLs. GitHub CI cannot fetch those.
Do not change the user-level default registry if you will submit. Restore https://registry.npmjs.org/ (or unset the override) before forge widget submit.
If neither public npm nor your institution's registry can serve the checkout, local widget create/preview cannot finish. Collect the support bundle and escalate.
Widget development
Widget name mismatch (-widget suffix)
Symptom: You create spend-chart but the preview picker shows spend-chart-widget.
Explanation: Web Nx generators often append -widget. The CLI accepts either form. Many mobile widgets have no suffix.
Web preview and the OLB playground
First compile looks stuck, or the browser never opens
Symptom: forge widget preview sits on the Nx compile, or prints Dev server not ready — remoteEntry.js was not detected in time / Mount API did not become ready in time and does not open a browser.
Explanation: The first compile often takes 2–5+ minutes. The CLI waits up to --ready-timeout seconds (default 300) for remoteEntry.js, then up to 20 seconds for the playground mount API on port 3001. If either is late, it prints a manual URL and skips opening the browser.
Solution: Wait until the Nx terminal shows a successful compile. Open the URL the CLI printed. That is http://localhost:4200 when the mount API succeeded, or the playground manager deep link (http://localhost:4200/playground?...) when it did not. Increase the wait with --ready-timeout if the machine is slow. Check Docker with:
cd ~/.forge/cdx-extensibility-apps/playground/web
docker compose ps
If Docker is down, start Docker Desktop and retry, or preview the Nx server only:
forge widget preview my-portfolio --no-playground
Blank page after the browser opens
Symptom: The playground loads but the widget slot is empty.
Solution:
- Confirm
docker compose psinplayground/webshows the stack healthy (shell on 4200, BFF on 3001 when preview needs the mount API). - Check the Nx terminal for compile errors.
- Reload
http://localhost:4200. Some Aspects register after the first load.
Playground port already in use
Symptom: forge playground up fails because a published compose port is taken (often 4200 or 3001; the stack also publishes other host ports).
Explanation: With the playground on, forge widget preview always moves the Nx dev server off 4200 onto 4300, then scans upward for a free port. The playground shell still binds host 4200. forge playground up does not remap those compose ports. Stop the conflicting process or container, then retry:
docker ps
docker stop <container-id>
forge playground up
Docker daemon not running
Symptom: Preview or forge playground up prints that Docker is not running or docker.sock is unreachable.
Solution: Open Docker Desktop and wait until docker info succeeds. To skip the playground: forge widget preview --no-playground or forge aspect preview --no-playground.
docker-compose.yml not found
Symptom: The CLI cannot find playground/web/docker-compose.yml.
Explanation: That file ships in the extensibility-apps checkout. Pull or recreate the managed checkout (Checkout not found or invalid), then retry. Doctor's docker.composeFile check reports the same.
Docker pull unauthorized (ghcr.io)
Symptom: docker pull or forge playground up --pull fails with unauthorized from ghcr.io.
Solution: Authenticate Docker with a GitHub PAT (classic read:packages, or fine-grained Packages: Read):
echo YOUR_GITHUB_PAT | docker login ghcr.io -u YOUR_GITHUB_USERNAME --password-stdin
forge playground up --pull
If the container is unhealthy, the CLI runs docker compose down, pull --ignore-buildable, and up -d --force-recreate, then waits again. From the checkout root doctor reported as ext.root:
cd playground/web
docker compose down && docker compose pull --ignore-buildable && docker compose up -d --force-recreate
Mobile preview
Mobile preview targets an iOS Simulator or Android Emulator by default (--mobile-device ios|android). The CLI prompts when both exist and aborts when neither does. Physical-device Expo Go is a fallback after emulator boot fails, not the primary path.
Dependencies not installed, or checkout too old
Symptom: Preview prints Dependencies not installed or This cdx-extensibility-apps checkout is too old for Forge mobile preview.
Solution: From the checkout root, run npm install (Reinstall dependencies). For an old checkout, update or recreate the managed cache (Checkout not found or invalid).
Widget not in the mobile registry
Symptom: Widget id "<name>" is not in playground/mobile-sandbox/registry/WIDGET_REGISTRY.ts.
Solution: The widget source may exist while the registry row was reverted. See Checkout refresh reverted my widget wiring.
QR code or Expo Go hang (physical device fallback)
Symptom: The iPhone Camera app shows "no usable data found," or Expo Go stays on "Opening project..."
Solution: The Camera app does not handle exp:// URLs. Use Expo Go's built-in scanner. Phone and machine must be on the same Wi-Fi. Prefer the simulator/emulator (--mobile-device ios or android) so you do not need that network path.
Do not start Expo by hand from playground/mobile-sandbox. That skips the widget preview target the CLI sets. Re-run forge widget preview <name> --platform mobile.
Forge opens the simulator or emulator itself (simctl on iOS). Press i in Metro only if auto-launch failed. If macOS blocked Automation (osascript -1743), pressing i can crash Metro. Do not press a in Metro on Android unless you need to reinstall Expo Go.
On Windows, if the Android emulator times out, enable Hyper-V or Windows Hypervisor Platform.
Metro Unable to resolve module
Symptom: Metro cannot resolve a module after you add a widget or dependency.
Explanation: By default, preview deletes Metro cache directories, then starts Expo with --clear. --no-clear-metro-cache skips only the directory delete. Expo still starts with --clear.
Solution: Re-run preview without --no-clear-metro-cache. If the missing module is a workspace package, run npm install at the checkout root.
Aspect development
Banner or Aspect not appearing after preview
Symptom: forge aspect preview opens the browser but the Aspect does not display.
Solutions:
- Reload
http://localhost:4200. The OLB shell runs injected Aspects on load. - Check
./aspects/and the browser console for syntax errors. A broken script fails silently. - Multiline
--messageissue: see the next section.
Multiline message not working
Symptom: --message with \n shows a literal backslash-n.
Solution: Use ANSI-C quoting ($'...') in bash/zsh:
# 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: welcome-banner shows Valued Customer, or personalized-toast shows Hi there!, instead of the user's name.
Explanation: Those templates call dbk.sessionInfo(), which exists in the OLB playground. --no-playground (local mock) has no session, so they fall back (Valued Customer vs there).
Solution: Run without --no-playground:
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 template) and --preset <id> loads, but the console shows script errors or 404 for SDK URLs.
Solutions:
-
Preview tries to clone
cdx-mockand start partner mocks when generated code or preset options reference:4011. If that fails, run a mock partner server on the host and port the preset expects (oftenhttp://localhost:4011). Preset URLs are stubs, not live vendor endpoints. -
Set
MOCK_PARTNERS_URLorMOCK_PARTNERS_PORTif your mock is not on the default port. -
Inspect generated code without a browser:
Bashforge aspect templates --id vendor-script-loader --preset engagement-script-loader --preview-code
Submission
Widget submission: repository not found
Symptom: forge widget submit prints Failed to access repository "…", Failed to clone: …, remote: Repository not found., or Could not determine repository name. Run forge repo status.
Explanation: The FI repository is missing, the name does not match, or GitHub auth cannot see it.
- Check repository status:
forge repo status - If no repository exists, create one:
forge repo init - Confirm you accepted the GitHub collaborator invitation
The CLI prints the repository name it tried so you can verify it with your administrator.
Localhost URLs in submission
Symptom: The CLI warns about localhost URLs during forge widget submit.
Explanation: Expected if you developed against the mock API. Those URLs will not work in production. The CLI prompts for production URLs before it opens the PR.
Skip the prompt with --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 or TypeScript errors before creating the PR. Markdownlint may show a non-blocking warning (markdown issues (non-blocking)).
Explanation: By default, submit runs Nx ESLint (nx lint), npm run typecheck in the widget directory, and markdownlint on README.md. Markdownlint warnings do not abort the submit. TypeScript failures do. ESLint rule failures abort; a missing ESLint plugin or missing @nx/eslint is a skip or warning. Common fixes:
no-console— remove debugconsole.logor replace it with proper logging.- TypeScript — run
npm run typecheckin the widget directory and fix the types. - Markdown — no trailing spaces, consistent heading levels, blank line before and after fenced code blocks.
To bypass the checks while debugging metadata:
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 widgets often declare tsup in devDependencies. Submit copies those tools into the FI repo root package.json on the web copy path and the mobile fallback copy path. The usual mobile path generates the widget with Nx in the FI clone, overlays src/, and merges missing devDependencies, peerDependencies, and build/dev scripts. It does not run that root-devDependency helper. If CI still fails:
-
Re-submit the widget so submit can sync the lockfile.
-
If CI uses strict
npm ciand the lockfile is still stale: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
If you pointed user-level npm at a private registry, that lockfile refresh can record private resolved URLs. Restore public npm before submit. See Corporate network and registry access.
Updating an existing widget PR
Push more commits to an open submission PR:
forge widget submit my-portfolio -u
# or: forge widget submit my-portfolio --update
Force a new PR even if one is already open:
forge widget submit my-portfolio --new
If you still need help
Send the platform team the following (redact tokens, cookies, and any _authToken / password lines from .npmrc or npm logs):
- The command that failed and the full terminal error
- OS and shell (for example Windows 11 23H2 + PowerShell; run
winveron Windows) forge --version,node -v,npm -vforge doctor --verbose --jsonsaved to a file (forge doctor --verbose --json > doctor.json)- For install issues: the npm timing/debug log from
npm install --timing --loglevel=verbose, plusnpm config get registryandnpm pingoutput - The checkout path from
ext.rootandgit statusinside that checkout
The JSON doctor report includes platform and Node version. Treat it as internal: it can contain username, org, institution, app ids, and absolute paths, but not session tokens.