{"record":{"id":"53aaca686cbbe59f","repo":"stablyai/orca","slug":"host-not-found","errorCode":null,"errorMessage":"Host not found","messagePattern":"Host not found","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"mobile/src/transport/host-store.ts","lineNumber":308,"sourceCode":"export async function retryPendingHostCredentialCleanup(): Promise<{\n  clearedCount: number\n  remainingIds: string[]\n  storageUnreadable: boolean\n}> {\n  return retryPendingHostCredentialCleanups((hostId) =>\n    deleteUnpairedHostCredentials(hostId, getHostCredentialWriteRevision(hostId))\n  )\n}\n\n// Why: single mutation pass commits name + endpoint atomically so a mid-save failure can't persist one without the other.\nexport async function updateHostNameAndEndpoint(\n  hostId: string,\n  updates: { name?: string; endpoint?: string }\n): Promise<void> {\n  await mutateStoredHosts((hosts) => {\n    const index = hosts.findIndex((host) => host.id === hostId)\n    if (index === -1) {\n      throw new Error('Host not found')\n    }\n    const next = hosts.slice()\n    next[index] = {\n      ...next[index]!,\n      ...(updates.name !== undefined ? { name: updates.name } : {}),\n      ...(updates.endpoint !== undefined ? { endpoint: updates.endpoint } : {})\n    }\n    return next\n  })\n}\n\nexport async function updateLastConnected(hostId: string): Promise<void> {\n  try {\n    await mutateStoredHosts((hosts) => {\n      const index = hosts.findIndex((h) => h.id === hostId)\n      if (index === -1) {\n        return hosts\n      }","sourceCodeStart":290,"sourceCodeEnd":326,"githubUrl":"https://github.com/stablyai/orca/blob/1136503c6a231a16dce8f921f6fadb63d181e8db/mobile/src/transport/host-store.ts#L290-L326","documentation":"updateHostNameAndEndpoint could not find the given hostId in the stored host list during its atomic name+endpoint mutation. The function runs inside mutateStoredHosts, which loads the current list via readStoredHostProfilesForMutation and findIndex. A -1 index means the host was removed or never existed when the rename/endpoint edit tried to commit.","triggerScenarios":"User opened the edit-host screen, then the host was removed (by duplicate-key collapse, another tab, or a relay upgrade) before the save landed; hostId is stale after a re-pair that changed the ID; a concurrent removeHost won the mutation chain.","commonSituations":"Editing a host name while a relay upgrade reassigns the ID; host removed in another screen while the edit form is open; stale hostId after re-pairing the same public key (ID may change); duplicate-key dedup removed the row.","solutions":["Catch 'Host not found' and refresh the host list, then close the edit form with a 'host no longer exists' message.","Reload the host list when the edit screen mounts/focuses to avoid a stale hostId.","Do NOT silently create a new host — that bypasses the user's removal intent.","If the rename is critical, re-resolve the host by publicKeyB64 to find its current ID."],"exampleFix":"// before\nconst index = hosts.findIndex((host) => host.id === hostId)\nif (index === -1) {\n  throw new Error('Host not found')\n}\n\n// after — caller-side recovery\ntry {\n  await updateHostNameAndEndpoint(hostId, updates)\n} catch (e) {\n  if (e.message === 'Host not found') {\n    await refreshHostList()\n    closeEditForm()\n    return\n  }\n  throw e\n}","handlingStrategy":"try-catch","validationCode":"// Verify the host still exists before opening the edit form\nconst hosts = await loadHosts()\nif (!hosts.some((h) => h.id === hostId)) {\n  closeEditForm()\n  return\n}","typeGuard":null,"tryCatchPattern":"try {\n  await updateHostNameAndEndpoint(hostId, updates)\n} catch (e) {\n  if (e.message === 'Host not found') {\n    await refreshHostList()\n    closeEditForm()\n    return\n  }\n  throw e\n}","preventionTips":["Reload the host list when the edit screen gains focus to avoid a stale hostId.","Catch 'Host not found' and refresh — do not silently recreate the host.","If the rename is critical, re-resolve the host by publicKeyB64 to find its current ID.","Cancel pending edits when a host removal is detected."],"tags":["host-store","host-profiles","concurrency","mobile"],"backgroundTag":null,"analyzedSha":"1136503c6a231a16dce8f921f6fadb63d181e8db","analyzedAt":"2026-08-12T23:15:58.167Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}