{"record":{"id":"e454eedcb048b2dc","repo":"PrefectHQ/fastmcp","slug":"app-bridge-js-not-found-in-ext-apps-tarball","errorCode":null,"errorMessage":"app-bridge.js not found in ext-apps tarball","messagePattern":"app-bridge\\.js not found in ext-apps tarball","errorType":"exception","errorClass":"RuntimeError","httpStatus":null,"severity":"error","filePath":"fastmcp_slim/fastmcp/cli/apps_dev.py","lineNumber":1355,"sourceCode":"\n    # -- Download and patch app-bridge.js (cached per ext-apps + SDK version) -\n    app_bridge_cache = (\n        Path(tempfile.gettempdir()) / f\"fastmcp-ext-apps-{version}-sdk-{sdk_version}.js\"\n    )\n    if app_bridge_cache.exists():\n        app_bridge_js = app_bridge_cache.read_text(encoding=\"utf-8\")\n        return app_bridge_js, import_map_json\n\n    npm_url = f\"https://registry.npmjs.org/@modelcontextprotocol/ext-apps/-/ext-apps-{version}.tgz\"\n    with httpx2.Client(timeout=30.0) as client:\n        resp = client.get(npm_url, follow_redirects=True)\n        resp.raise_for_status()\n        data = resp.content\n\n    with tarfile.open(fileobj=io.BytesIO(data), mode=\"r:gz\") as tar:\n        member = tar.extractfile(\"package/dist/src/app-bridge.js\")\n        if member is None:\n            raise RuntimeError(\"app-bridge.js not found in ext-apps tarball\")\n        app_bridge_js = member.read().decode()\n\n    # Rewrite bare SDK module specifiers to concrete esm.sh URLs\n    for sdk_path in (\"types.js\", \"shared/protocol.js\"):\n        app_bridge_js = app_bridge_js.replace(\n            f'from\"@modelcontextprotocol/sdk/{sdk_path}\"',\n            f'from\"{sdk_base}/{sdk_path}\"',\n        )\n\n    app_bridge_cache.write_text(app_bridge_js, encoding=\"utf-8\")\n    return app_bridge_js, import_map_json\n\n\nasync def _fetch_app_bridge_bundle(\n    version: str,\n    sdk_version: str,\n) -> tuple[str, str]:\n    \"\"\"Async wrapper around _fetch_app_bridge_bundle_sync.\"\"\"","sourceCodeStart":1337,"sourceCodeEnd":1373,"githubUrl":"https://github.com/PrefectHQ/fastmcp/blob/1f021142978e0861cd910c8df4e8074bc7cf3978/fastmcp_slim/fastmcp/cli/apps_dev.py#L1337-L1373","documentation":"The dev tooling downloads the @modelcontextprotocol/ext-apps npm tarball and extracts package/dist/src/app-bridge.js from it. tar.extractfile returns None when the member path doesn't exist, which is converted into this RuntimeError. It means the tarball layout changed (path moved/renamed) or the wrong/empty tarball was downloaded.","triggerScenarios":"ext-apps published a new version where app-bridge.js lives at a different path (no dist/src/ layout), or the fetched artifact isn't the expected gzipped package tarball.","commonSituations":"Unpinned ext-apps version pulling a restructured release; npm registry/proxy returning a 404 page saved as a tarball; offline caches serving stale artifacts.","solutions":["Check the ext-apps version being fetched; pin to a known-good version with app-bridge.js at package/dist/src/","List the tarball members to find the new path and update the extractfile path in apps_dev.py","Verify the downloaded bytes are a valid gzip tarball (tar -tzf) — fix registry/proxy issues if not","Retry after clearing any package cache"],"exampleFix":null,"handlingStrategy":"validation","validationCode":"import io, tarfile\nwith tarfile.open(fileobj=io.BytesIO(data), mode='r:gz') as tar:\n    names = tar.getnames()\n    assert 'package/dist/src/app-bridge.js' in names, names[:20]","typeGuard":null,"tryCatchPattern":"try:\n    bundle = _fetch_app_bridge_bundle_sync(...)\nexcept RuntimeError as exc:\n    if 'app-bridge.js not found' in str(exc):\n        logger.warning('ext-apps tarball layout changed; pin a known-good version')\n    else:\n        raise","preventionTips":["Pin the ext-apps version instead of floating to latest","Verify downloaded artifacts are valid gzip tarballs before extracting","When upgrading ext-apps, diff the package layout"],"tags":["packaging","tarball","upstream-drift","npm"],"backgroundTag":"artifact-layout-changed","analyzedSha":"1f021142978e0861cd910c8df4e8074bc7cf3978","analyzedAt":"2026-08-29T14:31:16.082Z","schemaVersion":2},"datasetVersion":"2026-08-29T17:17:51.833Z"}