{"record":{"id":"ad6410b9f8427a04","repo":"siyuan-note/siyuan","slug":"conf-language-330","errorCode":null,"errorMessage":"Conf.Language(330)","messagePattern":"Conf\\.Language\\(330\\)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"kernel/model/import_obsidian.go","lineNumber":280,"sourceCode":"\ttask := &obsidianTask{TaskID: taskID, State: ObsidianTaskStateQueued, Message: \"Waiting to analyze\", Cancel: cancel}\n\tobsidianTasks[taskID] = task\n\tobsidianActive = taskID\n\tret := snapshotObsidianTask(task)\n\tobsidianTasksMu.Unlock()\n\n\tif replacedTaskID != \"\" {\n\t\tremoveObsidianTemp(replacedTaskID)\n\t}\n\tgo analyzeObsidianVaultTask(ctx, taskID, localPath)\n\treturn ret, nil\n}\n\nfunc GetObsidianVaultTask(taskID string) (*ObsidianVaultTask, error) {\n\tobsidianTasksMu.Lock()\n\tdefer obsidianTasksMu.Unlock()\n\ttask := obsidianTasks[taskID]\n\tif task == nil {\n\t\treturn nil, errors.New(Conf.Language(330))\n\t}\n\treturn snapshotObsidianTask(task), nil\n}\n\nfunc CancelObsidianVaultTask(taskID string) (*ObsidianVaultTask, error) {\n\tobsidianTasksMu.Lock()\n\ttask := obsidianTasks[taskID]\n\tif task == nil {\n\t\tobsidianTasksMu.Unlock()\n\t\treturn nil, errors.New(Conf.Language(330))\n\t}\n\tif !isObsidianCancellableState(task.State) {\n\t\tret := snapshotObsidianTask(task)\n\t\tobsidianTasksMu.Unlock()\n\t\treturn ret, errors.New(Conf.Language(331))\n\t}\n\tif task.Cancel != nil {\n\t\ttask.Cancel()","sourceCodeStart":262,"sourceCodeEnd":298,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/8641553a1f07374001902d3ce773285db1292b2d/kernel/model/import_obsidian.go#L262-L298","documentation":"`GetObsidianVaultTask` looks up an import task by ID in the in-memory `obsidianTasks` map. If the ID is unknown — or the task has been evicted after completion/expiry — it returns the localized message 'Obsidian Vault import task not found or expired' (Conf.Language(330)) instead of a snapshot.","triggerScenarios":"Calling `GetObsidianVaultTask`/`CancelObsidianVaultTask` with a taskID that was never created, mistyped, belongs to a previous kernel process, or whose task record was removed after reaching a terminal state.","commonSituations":"Client caches an old task ID across a kernel restart (the registry is in-memory only); polling a finished task after cleanup; a race where two pollers use a stale ID from a failed create response.","solutions":["Use the task ID exactly as returned by the import-start call; do not fabricate or reuse IDs across sessions","Treat this error as terminal: stop polling and re-read the current task list / start a fresh import","After a kernel restart, obtain a new task ID — old IDs are invalid by design","Guard client-side: stop polling once the task reports a terminal state instead of continuing after cleanup"],"exampleFix":"// before\ntask, err := GetObsidianVaultTask(oldID) // stale after restart -> Conf.Language(330)\n// after\ntask, err := GetObsidianVaultTask(oldID)\nif err != nil {\n    oldID = \"\" // start a new import and capture its fresh task ID\n}","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"const task = await getObsidianVaultTask(taskID).catch(e => {\n  if (e.code === 330) { taskID = null; return null } // stale/expired: reset and re-create\n  throw e\n})","preventionTips":["Only use task IDs returned by the import-start API; never construct or reuse old ones","Clear cached task IDs when the kernel restarts (the registry is in-memory)","Stop polling once a task reaches a terminal state instead of querying after cleanup","On this error, re-list or restart the import rather than retrying the same ID"],"tags":["obsidian","task-management","not-found","api"],"backgroundTag":"entity-not-found","analyzedSha":"8641553a1f07374001902d3ce773285db1292b2d","analyzedAt":"2026-09-11T16:08:28.414Z","contentChangedAt":"2026-09-11T16:08:28.414Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}