aaif-goose/goose · error
Invalid deeplink or recipe format
Error message
Invalid deeplink or recipe format
What it means
Thrown by the recipe import dialog in the goose desktop app when parseDeeplink returns null. parseDeeplink (ui/desktop/src/recipe/index.ts:93) returns null — never throws — whenever the trimmed input does not start with 'goose://recipe?config=', has an empty payload, fails decodeRecipe, or the decoded recipe lacks title/description or both instructions and prompt. The form collapses all of those distinct failures into this single message.
Source
Thrown at ui/desktop/src/components/recipes/ImportRecipeForm.tsx:126
const importRecipeForm = useForm({
defaultValues: {
deeplink: '',
recipeUploadFile: null as File | null,
},
validators: {
onChange: importRecipeSchema,
},
onSubmit: async ({ value }) => {
setImporting(true);
try {
let recipe: Recipe;
// Parse recipe from either deeplink or recipe file
if (value.deeplink && value.deeplink.trim()) {
const parsedRecipe = await parseDeeplink(value.deeplink.trim());
if (!parsedRecipe) {
throw new Error('Invalid deeplink or recipe format');
}
recipe = parsedRecipe;
} else {
const fileContent = await value.recipeUploadFile!.text();
recipe = await parseRecipeFromFile(fileContent);
}
await saveRecipe(recipe, null);
// Reset dialog state
importRecipeForm.reset({
deeplink: '',
recipeUploadFile: null,
});
onClose();
onSuccess();
View on GitHub (pinned to 3810898a74)
Solutions
- Paste a link that starts exactly with goose://recipe?config= — generate one from the deeplink generator page or the desktop share flow
- If importing a YAML file, leave the deeplink field empty and use the file picker; a non-empty deeplink always takes precedence
- Re-copy the entire link (truncated config payloads fail decode)
- If you generate the links yourself, ensure the encoded recipe has title, description, and instructions or prompt
Example fix
// before
const parsedRecipe = await parseDeeplink(value.deeplink.trim());
if (!parsedRecipe) {
throw new Error('Invalid deeplink or recipe format');
}
// after
const link = value.deeplink.trim();
if (!link.startsWith('goose://recipe?config=')) {
importRecipeForm.setError('deeplink', 'Link must start with goose://recipe?config=');
return;
}
const parsedRecipe = await parseDeeplink(link);
if (!parsedRecipe) {
importRecipeForm.setError(
'deeplink',
'Decoded recipe is invalid: it needs title, description, and instructions or prompt'
);
return;
} Defensive patterns
Strategy: try-catch
Validate before calling
const link = value.deeplink.trim();
if (link && !link.startsWith('goose://recipe?config=')) {
importRecipeForm.setError('deeplink', 'Link must start with goose://recipe?config=');
} Type guard
const isRecipe = (r: Recipe | null): r is Recipe => r !== null && Boolean(r.title) && Boolean(r.description) && (Boolean(r.instructions) || Boolean(r.prompt));
Try / catch
try {
const recipe = await parseDeeplink(link);
if (!isRecipe(recipe)) {
importRecipeForm.setError('deeplink', 'Recipe needs title, description, and instructions or prompt');
return;
}
await saveRecipe(recipe, null);
} catch (e) {
importRecipeForm.setError('deeplink', e instanceof Error ? e.message : 'Import failed');
} finally {
setImporting(false);
} Prevention
- Generate links from the deeplink generator page or the desktop share flow instead of hand-building them
- Paste complete links; truncated config= payloads always fail decode
- Use the file picker for YAML imports and keep the deeplink field empty
When it happens
Trigger: Pasting raw recipe YAML into the deeplink field; pasting a goose:// link for a non-recipe target such as goose://extension?...; a config= payload that is truncated so base64/decode fails; a decoded recipe that has title and description but neither instructions nor prompt.
Common situations: Confusing the deeplink field with the file import path; links copied from chat clients that ellipsize long URLs; recipes authored by hand that omit instructions/prompt; whitespace or a newline inside the pasted link breaking the prefix check or payload.
Related errors
- Failed to parse recipe from file.
- Failed to open recipe: {}
- Invalid parameter format: '{}'. Expected format: key=value
- Failed to encode recipe: {}
- Missing 'instructions' in json response
AI-assisted analysis of aaif-goose/goose@3810898a74 (2026-08-16).
Data as JSON: /api/errors/aaac6dee20d3021d.
Report an issue: GitHub.