{"record":{"id":"bbe7717ce2bd5246","repo":"aaif-goose/goose","slug":"failed-to-parse-recipe-from-file","errorCode":null,"errorMessage":"Failed to parse recipe from file.","messagePattern":"Failed to parse recipe from file\\.","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"ui/desktop/src/components/schedule/ScheduleModal.tsx","lineNumber":143,"sourceCode":"        }\n      }\n    }\n  }, [isOpen, schedule, initialDeepLink, handleDeepLinkChange]);\n\n  const handleBrowseFile = async () => {\n    const fileResponse = await window.electron.selectRecipeFile();\n    if (fileResponse) {\n      if (fileResponse.filePath.endsWith('.yaml') || fileResponse.filePath.endsWith('.yml')) {\n        setRecipeSourcePath(fileResponse.filePath);\n        setInternalValidationError(null);\n\n        try {\n          if (!fileResponse.found || fileResponse.error) {\n            throw new Error(intl.formatMessage(i18n.failedReadFile));\n          }\n          const recipe = await parseRecipeFromFile(fileResponse.file);\n          if (!recipe) {\n            throw new Error(intl.formatMessage(i18n.failedParseRecipe));\n          }\n          setParsedRecipe(recipe);\n          if (recipe.title) {\n            setScheduleIdFromTitle(recipe.title);\n          }\n        } catch (e) {\n          setParsedRecipe(null);\n          setInternalValidationError(\n            e instanceof Error ? e.message : intl.formatMessage(i18n.failedParseRecipe)\n          );\n        }\n      } else {\n        setInternalValidationError(intl.formatMessage(i18n.invalidFileType));\n      }\n    }\n  };\n\n  const handleLocalSubmit = async (event: FormEvent) => {","sourceCodeStart":125,"sourceCodeEnd":161,"githubUrl":"https://github.com/aaif-goose/goose/blob/3810898a7447ec3299be72e223d3570a7aabf0ab/ui/desktop/src/components/schedule/ScheduleModal.tsx#L125-L161","documentation":"Shown by the schedule modal in the goose desktop app when the file was read successfully (found is true, no error) but parseRecipeFromFile returned a falsy value. parseRecipeFromFile delegates to the ACP recipe parser; when the content is empty or is YAML that does not represent a recipe, the parser can return null/undefined rather than throw, and this branch converts that into the localized 'Failed to parse recipe from file.' message. Distinct from error 45: the bytes were read; they just are not a valid goose recipe.","triggerScenarios":"Selecting an empty .yaml file; selecting YAML that parses but has no recipe structure (missing title/instructions/prompt at the top level); selecting a YAML front-matter fragment or unrelated config file renamed to .yml.","commonSituations":"Hand-authoring recipe YAML for the scheduler without the required recipe fields; exporting partial recipes from other tools; picking a CI or docker-compose YAML by mistake because the dialog filters only on extension.","solutions":["Open the selected YAML and confirm it is a goose recipe: top-level title/description plus instructions or prompt","Get known-good YAML by exporting a working recipe (goose CLI or desktop recipe UI) and comparing structure","Make sure the file is non-empty and starts at column 0 (no stray BOM or leading blank document markers)"],"exampleFix":null,"handlingStrategy":"validation","validationCode":"const text = fileResponse.file ?? '';\nconst looksLikeGooseRecipe =\n  text.trim().length > 0 &&\n  /(^|\\n)(instructions|prompt):/.test(text) &&\n  /(^|\\n)(title|name):/.test(text);","typeGuard":"const isParsedRecipe = (r: Recipe | null | undefined): r is Recipe =>\n  Boolean(r) && Boolean((r as Recipe).title);","tryCatchPattern":"try {\n  const recipe = await parseRecipeFromFile(fileResponse.file);\n  if (!isParsedRecipe(recipe)) {\n    setInternalValidationError(intl.formatMessage(i18n.failedParseRecipe));\n    return;\n  }\n  setParsedRecipe(recipe);\n} catch (e) {\n  setInternalValidationError(e instanceof Error ? e.message : intl.formatMessage(i18n.failedParseRecipe));\n}","preventionTips":["Author recipes by exporting a working recipe and editing the YAML","Eyeball the YAML for top-level title/description plus instructions or prompt before scheduling","Do not rely on the .yaml extension alone — the dialog filters on extension, not content"],"tags":["yaml","recipe","parsing","desktop","scheduling"],"backgroundTag":null,"analyzedSha":"3810898a7447ec3299be72e223d3570a7aabf0ab","analyzedAt":"2026-08-16T10:14:26.282Z","schemaVersion":2},"datasetVersion":"2026-08-16T13:17:31.715Z"}