{"record":{"id":"e9422a722997560e","repo":"actualbudget/actual","slug":"schedule-id-not-found","errorCode":null,"errorMessage":"Schedule ${id} not found","messagePattern":"Schedule (.+?) not found","errorType":"exception","errorClass":"APIError","httpStatus":null,"severity":"error","filePath":"packages/loot-core/src/server/api.ts","lineNumber":952,"sourceCode":"  const partialSchedule = {\n    name: internalSchedule.name,\n    posts_transaction: internalSchedule.posts_transaction,\n  };\n  return handlers['schedule/create']({\n    schedule: partialSchedule,\n    conditions: internalSchedule._conditions,\n  });\n});\n\nhandlers['api/schedule-update'] = withMutation(async function ({\n  id,\n  fields,\n  resetNextDate,\n}) {\n  checkFileOpen();\n  const { data } = await aqlQuery(q('schedules').filter({ id }).select('*'));\n  if (!data || data.length === 0) {\n    throw APIError(`Schedule ${id} not found`);\n  }\n\n  const sched = data[0] as ScheduleEntity;\n  let conditionsUpdated = false;\n  // Find all indices to avoid direct assignment\n  const payeeIndex = sched._conditions.findIndex(c => c.field === 'payee');\n  const accountIndex = sched._conditions.findIndex(c => c.field === 'account');\n  const dateIndex = sched._conditions.findIndex(c => c.field === 'date');\n  const amountIndex = sched._conditions.findIndex(c => c.field === 'amount');\n\n  for (const key in fields) {\n    const typedKey = key as keyof APIScheduleEntity;\n    const value = fields[typedKey];\n\n    switch (typedKey) {\n      case 'name': {\n        const newName = String(value);\n        const { data: existing } = await aqlQuery(","sourceCodeStart":934,"sourceCodeEnd":970,"githubUrl":"https://github.com/actualbudget/actual/blob/d4334cb6e6123f4d3bcea1ad6166608884c7e658/packages/loot-core/src/server/api.ts#L934-L970","documentation":"api.updateSchedule() looks up the schedule row via an AQL query before mutating conditions. If no schedule with that id exists in the schedules table, the handler throws this APIError naming the missing id.","triggerScenarios":"Calling api.updateSchedule(id, fields, resetNextDate) with an id that is not a schedule id (e.g. a transaction or account id), an id from a different budget, or an id of a schedule already deleted.","commonSituations":"Stale references after re-importing or recreating a budget; passing the payee id or transaction id instead of the schedule id; concurrent deletion of the schedule between fetch and update.","solutions":["Verify the id by listing schedules and matching (via aqlQuery on q('schedules') or the UI)","Re-fetch schedule ids after any budget import/reset — don't persist schedule ids across budget rebuilds","Log the id being passed and confirm the producer of that id returns schedule entities"],"exampleFix":"// before\nawait api.updateSchedule(someRow.id, fields);\n// after\nconst { data } = await api.aqlQuery(q('schedules').filter({ id: someRow.id }).select('*'));\nif (data && data.length) await api.updateSchedule(someRow.id, fields);","handlingStrategy":"validation","validationCode":"const { data } = await aqlQuery(q('schedules').filter({ id }).select('*'));\nif (!data || data.length === 0) throw APIError(`Schedule ${id} not found`);","typeGuard":"function scheduleRowExists(res) {\n  return Array.isArray(res?.data) && res.data.length > 0;\n}","tryCatchPattern":"try {\n  await updateSchedule(id, fields);\n} catch (e) {\n  if (e instanceof APIError && e.message.includes('not found')) {\n    return { ok: false, reason: 'missing-schedule' };\n  }\n  throw e;\n}","preventionTips":["Resolve ids through the schedules table only","Purge cached schedule ids after budget resets","Return structured not-found results to callers"],"tags":["api","schedules","not-found"],"backgroundTag":"entity-not-found","analyzedSha":"d4334cb6e6123f4d3bcea1ad6166608884c7e658","analyzedAt":"2026-08-29T01:02:11.213Z","schemaVersion":2},"datasetVersion":"2026-08-29T02:17:18.158Z"}