{"record":{"id":"38f039697edc888d","repo":"stablyai/orca","slug":"recipe-not-found-runtime-recipeid","errorCode":null,"errorMessage":"Recipe not found: ${runtime.recipeId}","messagePattern":"Recipe not found: (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/main/ipc/ephemeral-vm-recipe-context.ts","lineNumber":121,"sourceCode":"  if (!runtime) {\n    throw new Error(`Unknown ephemeral VM runtime: ${runtimeId}`)\n  }\n  if (!runtime.repoId) {\n    throw new Error(`Ephemeral VM runtime has no repo id: ${runtimeId}`)\n  }\n  const repo = getRecipeRepo(store, runtime.repoId)\n  if (!repo.ok) {\n    throw new Error(repo.message)\n  }\n  // Pre-snapshot runtimes can only be attributed to repo-owned recipes. Never\n  // substitute a later same-id plugin recipe for an older runtime lifecycle.\n  const recipe =\n    runtime.recipe ??\n    (loadHooks(repo.repo.path)?.environmentRecipes ?? []).find(\n      (entry) => entry.id === runtime.recipeId\n    )\n  if (!recipe) {\n    throw new Error(`Recipe not found: ${runtime.recipeId}`)\n  }\n  return { runtime, repo, recipe }\n}\n\nexport function resolveRecipeForRepo(\n  repoPath: string,\n  recipeId: string,\n  pluginRecipes: readonly OrcaVmRecipe[] = []\n): OrcaVmRecipe | null {\n  return (\n    combineEphemeralVmRecipes(loadHooks(repoPath)?.environmentRecipes ?? [], pluginRecipes).find(\n      (recipe) => recipe.id === recipeId\n    ) ?? null\n  )\n}\n\n/** Project-owned recipes are authoritative for their repository and shadow\n * same-id global plugin recipes without disabling the rest of the pack. */","sourceCodeStart":103,"sourceCodeEnd":139,"githubUrl":"https://github.com/stablyai/orca/blob/1136503c6a231a16dce8f921f6fadb63d181e8db/src/main/ipc/ephemeral-vm-recipe-context.ts#L103-L139","documentation":"Thrown by `getRuntimeRecipeContext` when the runtime record exists and has a `repoId`, but no recipe with id `runtime.recipeId` is found. The resolver tries `runtime.recipe` (a snapshot retained on the record) first, then falls back to the repo's current `environmentRecipes` loaded via `loadHooks(repo.repo.path)`. A miss means the recipe was removed from `.orca/hooks` after the runtime was created and no snapshot was kept on the runtime record (a pre-snapshot runtime).","triggerScenarios":"A pre-snapshot runtime whose `recipeId` no longer exists in the owning repo's `.orca/hooks` environment recipes, and whose runtime record carries no `runtime.recipe` snapshot.","commonSituations":"Repo's `.orca/hooks` recipe was renamed/deleted between runtime creation and a later operation that needs recipe context; upgrading Orca across a version where recipe ids changed; a runtime record written before the snapshot field was introduced.","solutions":["Restore the recipe with id `runtime.recipeId` in the repo's `.orca/hooks`, or re-add it under the same id.","If restoration is impossible, mark the runtime as orphaned and offer the user a recreate-from-current-recipes flow.","For runtimes you create going forward, ensure the runtime record stores a recipe snapshot so later repo edits cannot orphan it."],"exampleFix":"// before\nconst ctx = getRuntimeRecipeContext(store, userDataPath, runtimeId)\n// throws 'Recipe not found: <id>'\n\n// after\ntry {\n  const ctx = getRuntimeRecipeContext(store, userDataPath, runtimeId)\n} catch (e) {\n  if (e.message.startsWith('Recipe not found:')) {\n    markRuntimeOrphaned(userDataPath, runtimeId)\n    promptRecreateFromCurrentRecipes()\n    return\n  }\n  throw e\n}","handlingStrategy":"try-catch","validationCode":"// Pre-check: does the repo still advertise the recipe, or does the runtime carry a snapshot?\nconst runtime = listEphemeralVmRuntimes(userDataPath).find((r) => r.id === runtimeId)\nif (!runtime) return null\nif (!runtime.recipe) {\n  const hooks = loadHooks(repo.repo.path)\n  if (!(hooks?.environmentRecipes ?? []).some((r) => r.id === runtime.recipeId)) {\n    // recipe gone; do not call getRuntimeRecipeContext\n    return null\n  }\n}\nreturn getRuntimeRecipeContext(store, userDataPath, runtimeId)","typeGuard":"function runtimeHasResolvableRecipe(runtime: { recipe?: unknown; recipeId: string }, recipes: { id: string }[]): boolean {\n  return Boolean(runtime.recipe) || recipes.some((r) => r.id === runtime.recipeId)\n}","tryCatchPattern":"try {\n  return getRuntimeRecipeContext(store, userDataPath, runtimeId)\n} catch (e) {\n  if (e instanceof Error && e.message.startsWith('Recipe not found:')) {\n    markRuntimeOrphaned(userDataPath, runtimeId)\n    promptRecreateFromCurrentRecipes()\n    return null\n  }\n  throw e\n}","preventionTips":["Always snapshot the recipe onto the runtime record at creation time so later repo edits cannot orphan it.","Warn before deleting/renaming a recipe in .orca/hooks if runtimes reference it.","Offer a recreate flow when a recipe is missing rather than leaving the runtime unusable."],"tags":["ephemeral-vm","recipe","lookup","state","migration"],"backgroundTag":null,"analyzedSha":"1136503c6a231a16dce8f921f6fadb63d181e8db","analyzedAt":"2026-08-12T23:15:58.167Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}