{"record":{"id":"2eaa45b944e02a96","repo":"home-assistant/core","slug":"no-valid-blueprint-found-in-the-gist-the-blueprin","errorCode":null,"errorMessage":"No valid blueprint found in the gist. The blueprint file needs to end with '.yaml'","messagePattern":"No valid blueprint found in the gist\\. The blueprint file needs to end with '\\.yaml'","errorType":"exception","errorClass":"HomeAssistantError","httpStatus":null,"severity":"error","filePath":"homeassistant/components/blueprint/importer.py","lineNumber":216,"sourceCode":"    filename: str | None = None\n    content: str\n\n    for filename, info in gist[\"files\"].items():\n        if not filename.endswith(\".yaml\"):\n            continue\n\n        content = info[\"content\"]\n        data = yaml_util.parse_yaml(content)\n\n        if not is_blueprint_config(data):\n            continue\n        assert isinstance(data, dict)\n\n        blueprint = Blueprint(data, schema=BLUEPRINT_SCHEMA)\n        break\n\n    if blueprint is None:\n        raise HomeAssistantError(\n            \"No valid blueprint found in the gist. The blueprint file needs to end with\"\n            \" '.yaml'\"\n        )\n    if TYPE_CHECKING:\n        assert isinstance(filename, str)\n\n    return ImportedBlueprint(\n        f\"{gist['owner']['login']}/{filename[:-5]}\", content, blueprint\n    )\n\n\nasync def fetch_blueprint_from_website_url(\n    hass: HomeAssistant, url: str\n) -> ImportedBlueprint:\n    \"\"\"Get a blueprint from our website.\"\"\"\n    if (WEBSITE_PATTERN.match(url)) is None:\n        raise UnsupportedUrl(\"Not a Home Assistant website URL\")\n","sourceCodeStart":198,"sourceCodeEnd":234,"githubUrl":"https://github.com/home-assistant/core/blob/58a3fdb3ea0538617f0a07efcfba6294de64fd59/homeassistant/components/blueprint/importer.py#L198-L234","documentation":"HomeAssistantError raised by blueprint.importer when fetching from a GitHub gist: none of the gist files qualified as a valid blueprint. The importer only considers files ending in .yaml, parses them, requires is_blueprint_config to pass (blueprint key with name and domain), and validates against BLUEPRINT_SCHEMA; if no file clears every check this error names the .yaml-extension requirement.","triggerScenarios":"Importing a gist URL where the blueprint is stored as .yml or .txt, the YAML has no blueprint: key, the schema validation fails (missing name/domain under blueprint), or the YAML doesn't parse. Every candidate file is skipped and blueprint remains None.","commonSituations":"Gist file named blueprint.yml instead of blueprint.yaml; blueprint body pasted without the blueprint header (name/domain/input); gist contains only a README or non-blueprint YAML; schema-breaking typo in the blueprint section.","solutions":["Rename the gist file so it ends exactly with .yaml","Ensure the file starts with a blueprint: block containing name and domain (plus input)","Validate the YAML locally (yamllint / HA check_config) and fix schema errors","Alternatively copy the blueprint into config/blueprints/automations/<name>.yaml manually"],"exampleFix":"# before: gist file blueprint.yml missing header\nmode: single\ntrigger: []\n# after: file renamed to blueprint.yaml with valid header\nblueprint:\n  name: Motion light\n  domain: automation\n  input:\n    motion_entity:\n      selector: { entity: { domain: binary_sensor } }\nmode: single\ntrigger: []","handlingStrategy":"validation","validationCode":"# Verify gist files locally before importing\nimport yaml, requests\n\ngist = requests.get(gist_api_url, timeout=10).json()\nfor fname, fdata in gist[\"files\"].items():\n    if fname.endswith(\".yaml\"):\n        parsed = yaml.safe_load(fdata[\"content\"])\n        assert isinstance(parsed, dict) and \"blueprint\" in parsed, f\"{fname} not a blueprint\"\n        break","typeGuard":"def gist_has_blueprint_file(gist: dict) -> bool:\n    \"\"\"True if at least one .yaml file is a blueprint config.\"\"\"\n    for f in gist.get(\"files\", {}).values():\n        if f[\"filename\"].endswith(\".yaml\"):\n            try:\n                data = yaml.safe_load(f[\"content\"])\n            except yaml.YAMLError:\n                continue\n            if (isinstance(data, dict)\n                    and isinstance(data.get(\"blueprint\"), dict)\n                    and {\"name\", \"domain\"} <= data[\"blueprint\"].keys()):\n                return True\n    return False","tryCatchPattern":"try:\n    imported = await importer.fetch_blueprint_from_gist(hass, gist_url)\nexcept HomeAssistantError as err:\n    if \"No valid blueprint found in the gist\" in str(err):\n        _LOGGER.warning(\"Gist rejected; ensure the file is .yaml with a blueprint header\")","preventionTips":["Name gist blueprint files with the .yaml extension exactly","Start the file with the blueprint: header (name, domain, input) — test locally with yaml.safe_load","Fork and fix non-conforming gists rather than importing them as-is"],"tags":["blueprint","importer","github-gist","yaml","schema"],"backgroundTag":null,"analyzedSha":"58a3fdb3ea0538617f0a07efcfba6294de64fd59","analyzedAt":"2026-08-14T20:54:38.818Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}