tinyhumansai/openhuman · error · Error
No screenshots found in ${screenshotDir}
Error message
No screenshots found in ${screenshotDir} What it means
uploadScreenshots() globs fastlane/screenshots/en-US for files ending exactly in '.png' (case-sensitive), sorts them, and refuses to run when the list is empty. This check deliberately runs BEFORE deleteExistingScreenshotSet(), so an empty directory fails safely instead of wiping the live screenshot set and uploading nothing.
Source
Thrown at scripts/ios-appstore-metadata.mjs:303
data: {
type: "appScreenshots",
id: reservation.data.id,
attributes: {
uploaded: true,
sourceFileChecksum: checksum,
},
},
});
console.log(`[ios-appstore-metadata] uploaded ${fileName}`);
}
async function uploadScreenshots(localization) {
const files = (await readdir(screenshotDir))
.filter((file) => file.endsWith(".png"))
.sort()
.map((file) => path.join(screenshotDir, file));
if (!files.length) {
throw new Error(`No screenshots found in ${screenshotDir}`);
}
await deleteExistingScreenshotSet(localization);
const set = await createScreenshotSet(localization);
for (const file of files) {
await uploadScreenshot(set, file);
}
}
await updateAppInfoLocalization();
const versionLocalization = await updateVersionLocalization();
await uploadScreenshots(versionLocalization);
console.log(
"[ios-appstore-metadata] metadata and screenshots submitted to App Store Connect.",
);
View on GitHub (pinned to a221052e0d)
Solutions
- Capture or copy the PNGs into <repo>/fastlane/screenshots/en-US before running
- Rename files to lowercase .png (e.g. `for f in *.PNG; do mv "$f" "${f%.PNG}.png"; done`)
- Re-run `node scripts/ios-appstore-metadata.mjs`; existing remote screenshots are only deleted once local files are confirmed present
Example fix
# before ls fastlane/screenshots/en-US # empty → script aborts # after mkdir -p fastlane/screenshots/en-US cp ~/captures/*.png fastlane/screenshots/en-US/ node scripts/ios-appstore-metadata.mjs
Defensive patterns
Strategy: validation
Validate before calling
import { readdir } from 'node:fs/promises';
const pngs = (await readdir('fastlane/screenshots/en-US')).filter(f => f.endsWith('.png'));
if (pngs.length === 0) {
console.error('No lowercase-.png screenshots in fastlane/screenshots/en-US — capture them first');
process.exit(1);
} Prevention
- Run the capture step (WDIO/fastlane snapshot) before the metadata script in the same pipeline and fail the pipeline if it produced zero PNGs
- Normalize screenshot filenames to lowercase .png — the glob is case-sensitive
- Keep the check-before-delete ordering: the empty-dir abort is what protects the live App Store screenshot set from being wiped
When it happens
Trigger: Fresh clone where screenshots were never captured; screenshots exist under a different locale directory (the path is hardcoded to fastlane/screenshots/en-US and does NOT follow ASC_LOCALE); files named .PNG/.jpg (endsWith('.png') is case-sensitive); wrong working directory assumptions.
Common situations: Running the metadata script before the screenshot-capture step on a new machine; a capture tool writing `01_home.PNG` uppercase extensions; screenshots landing in fastlane/screenshots/de-DE while the script only reads en-US.
Related errors
- asset upload failed: ${res.status} ${res.statusText} ${await
- ASC_KEY_ID, ASC_ISSUER_ID, and ASC_KEY_PATH are required.
- ${method} ${resourcePath} failed: ${message}
- No appInfos found for app ${appId}.
- ${name} requires a value
AI-assisted analysis of tinyhumansai/openhuman@a221052e0d (2026-08-16).
Data as JSON: /api/errors/709993206fe4693f.
Report an issue: GitHub.