Troubleshooting
What the messages mean and how to fix them.
validate / generate
| Message | Meaning / fix |
|---|---|
No store-shots.config.json found | Run from inside an app, pass --project <app-dir>, or store-shots init --project <app-dir> |
content.missing-locale | Create store/content/<locale>.json ({"locale":"de-DE","screens":{}}) or remove the locale from config.locales |
content.missing-field / content.missing-screen | Copy is missing for that locale/screen; strict mode blocks the job. Edit in the UI or the JSON |
content.unused-field (warning) | The screen's template does not show that field (an eyebrow under Full Bleed Card). The copy is kept for switching back; delete it if you do not need it |
content.unknown-field | No template knows that field name: a typo, or a slide field (headline2) on a screen with one slide |
content.starter-copy (warning) | A theme's prompt ("What does this screen let you do?") is still the copy. Write the screen's own; readiness fails until every prompt is gone |
content.glyph-missing | A character is not covered by any local font. store-shots fonts add "<family>" (the message suggests one) and list it in brand.font.fallbacks |
font.missing | brand.font.family (or headlineFont) is not downloaded: store-shots fonts add "<family>" --project <app> |
source.missing | Raw capture not found at store/raw/<device>/<locale>/<file>; capture it (store-shots capture --screen <id> --device iphone --locale <l>) or fix source.filePattern |
source.aspect (warning) | Capture aspect ratio differs from the target; the shell uses object-fit: cover, so it still renders, but use the right simulator (6.9" iPhone Pro Max, 13" iPad Pro) for fidelity |
render.overflow ... even at the minimum allowed size | Copy is too long for the box at the template's minimum font scale; shorten it or widen textWidth |
render.text-overlaps-device (warning) | Text box intersects the device. Intentional designs can ignore it; set validation.failOnTextOverlap to make it an error |
content.store-claims (warning) | Screenshot copy shows a price, discount, URL, ©, another platform or an Apple recognition, which Apple's asset guidelines rule out. Reword it |
plan.too-few / plan.too-many | Screens per target/locale outside validation.screensPerTarget (Apple: 1–10) |
manifest.override-invalid | An override key/value is outside the template's schema; see the allowed list in the hint |
React is not defined | The CLI was run with a tsconfig other than the tool's. Use bin/store-shots.mjs / npx store-shots, which pin it |
Playwright: Executable doesn't exist | npx playwright install chromium inside tools/store-shots |
Readiness
Metadata present for every localefails → Listing editsfastlane/metadata/<locale>/*.txt; Start from the default language fills a new one.Screenshots completefails → generate; the check wants exact target dimensions and no alpha. Hand-made files that match a target count too; files of other sizes are listed as "matches no configured target" (warning).App icon ... has an alpha channelis a warning: Expo prebuild flattens the iOS icon.Screenshot sets cover the sizes Apple requireswarns without a 6.1" iPhone set: Apple names it required, but scales a 6.9" set down when it is missing. Addiphone-6.1-1206x2622to the targets; it renders from the same captures. It fails whenios.supportsTabletis true and there is no iPad 13" set.Keywords follow Apple's guidancefails over 100 bytes (Japanese, Chinese, Arabic and Cyrillic take 2-3 bytes per character) and warns on plurals of included words, category names, "app", repeated words,#/@and terms of two characters or fewer.
Fastlane runner
- Upload lanes are disabled while readiness fails; enter an override reason to force them (logged).
lane "<name>" not found in fastlane/Fastfile→ the app's Fastfile lacks the lane; add it (see Uploading with fastlane) or pointfastlane.lanesat the lane it has.- Output is the real
fastlaneoutput; credentials and ASC behaviour are fastlane's, not the tool's. - fastlane is found at
/opt/homebrew/bin/fastlane,/usr/local/bin/fastlane,$STORE_SHOTS_FASTLANE, or onPATH.
Capture
No booted simulator→ boot one in Simulator.app.store-shots capture --listshows what is booted.already exists; pass --force→ captures are never overwritten silently.- Non-localized screens (
source.localized: false) only accept the default locale. - Clean status bar:
--clean-status-bar(9:41, full battery/signal). Other locales: the command prints thesimctlcommands to switch the simulator language.
Determinism
Outputs are byte-identical for identical inputs (fonts bundled/locally downloaded, fixed viewport,
animations disabled, Sharp flatten). If a second generate re-renders everything, something in
inputsSha256 changed: the capture, copy, overrides, brand, output settings, fonts or the tool
version. --force re-renders regardless.