"type": "boolean",
       "default": true
     },
+    "ExtraQuestItems": {
+      "description": "Some quests (such as Ixal) add quest items to gathering nodes, but there's no clear connection between the item and the node in the sheets",
+      "type": "array",
+      "items": {
+        "type": "integer",
+        "minimum": 2000000
+      }
+    },
     "Groups": {
       "type": "array",
       "items": {
 
                                 Assignment(nameof(GatheringRoot.FlyBetweenNodes), root.FlyBetweenNodes,
                                         emptyRoot.FlyBetweenNodes)
                                     .AsSyntaxNodeOrToken(),
+                                AssignmentList(nameof(GatheringRoot.ExtraQuestItems), root.ExtraQuestItems).AsSyntaxNodeOrToken(),
                                 AssignmentList(nameof(GatheringRoot.Groups), root.Groups).AsSyntaxNodeOrToken()))));
         }
         catch (Exception e)
 
 
     public List<QuestStep> Steps { get; set; } = [];
     public bool? FlyBetweenNodes { get; set; }
+    public List<uint> ExtraQuestItems { get; set; } = [];
     public List<GatheringNodeGroup> Groups { get; set; } = [];
 }
 
 {
     private readonly IContextMenu _contextMenu;
     private readonly QuestController _questController;
+    private readonly GatheringPointRegistry _gatheringPointRegistry;
     private readonly GatheringData _gatheringData;
     private readonly QuestRegistry _questRegistry;
     private readonly QuestData _questData;
     public ContextMenuController(
         IContextMenu contextMenu,
         QuestController questController,
+        GatheringPointRegistry gatheringPointRegistry,
         GatheringData gatheringData,
         QuestRegistry questRegistry,
         QuestData questData,
     {
         _contextMenu = contextMenu;
         _questController = questController;
+        _gatheringPointRegistry = gatheringPointRegistry;
         _gatheringData = gatheringData;
         _questRegistry = questRegistry;
         _questData = questData;
         if (classJob != currentClassJob && currentClassJob is EClassJob.Miner or EClassJob.Botanist)
             return;
 
-        if (!_gatheringData.TryGetGatheringPointId(itemId, classJob, out _))
+        if (!_gatheringPointRegistry.TryGetGatheringPointId(itemId, classJob, out _))
         {
             _logger.LogInformation("No gathering point found for {ClassJob}.", classJob);
             return;
 
     private readonly AetheryteFunctions _aetheryteFunctions;
     private readonly ExcelFunctions _excelFunctions;
     private readonly QuestController _questController;
-    private readonly GatheringData _gatheringData;
     private readonly GatheringPointRegistry _gatheringPointRegistry;
     private readonly QuestRegistry _questRegistry;
     private readonly QuestData _questData;
         AetheryteFunctions aetheryteFunctions,
         ExcelFunctions excelFunctions,
         QuestController questController,
-        GatheringData gatheringData,
         GatheringPointRegistry gatheringPointRegistry,
         QuestRegistry questRegistry,
         QuestData questData,
         _aetheryteFunctions = aetheryteFunctions;
         _excelFunctions = excelFunctions;
         _questController = questController;
-        _gatheringData = gatheringData;
         _gatheringPointRegistry = gatheringPointRegistry;
         _questRegistry = questRegistry;
         _questData = questData;
         if (step != null && (step.TerritoryId != _clientState.TerritoryType || step.TargetTerritoryId == null) &&
             step.InteractionType == EInteractionType.Gather)
         {
-            if (_gatheringData.TryGetGatheringPointId(step.ItemsToGather[0].ItemId,
+            if (_gatheringPointRegistry.TryGetGatheringPointId(step.ItemsToGather[0].ItemId,
                     (EClassJob?)_clientState.LocalPlayer?.ClassJob.RowId ?? EClassJob.Adventurer,
                     out GatheringPointId? gatheringPointId) &&
                 _gatheringPointRegistry.TryGetGatheringPoint(gatheringPointId, out GatheringRoot? root))
 
 using System.Diagnostics;
 using System.Diagnostics.CodeAnalysis;
 using System.IO;
+using System.Linq;
 using System.Text.Json;
 using Dalamud.Plugin;
+using LLib.GameData;
 using Microsoft.Extensions.Logging;
+using Questionable.Data;
 using Questionable.GatheringPaths;
 using Questionable.Model;
 using Questionable.Model.Gathering;
 {
     private readonly IDalamudPluginInterface _pluginInterface;
     private readonly QuestRegistry _questRegistry;
+    private readonly GatheringData _gatheringData;
     private readonly ILogger<QuestRegistry> _logger;
 
     private readonly Dictionary<GatheringPointId, GatheringRoot> _gatheringPoints = new();
 
-    public GatheringPointRegistry(IDalamudPluginInterface pluginInterface, QuestRegistry questRegistry,
+    public GatheringPointRegistry(IDalamudPluginInterface pluginInterface,
+        QuestRegistry questRegistry,
+        GatheringData gatheringData,
         ILogger<QuestRegistry> logger)
     {
         _pluginInterface = pluginInterface;
         _questRegistry = questRegistry;
+        _gatheringData = gatheringData;
         _logger = logger;
 
         _questRegistry.Reloaded += OnReloaded;
     public bool TryGetGatheringPoint(GatheringPointId gatheringPointId, [NotNullWhen(true)] out GatheringRoot? gatheringRoot)
         => _gatheringPoints.TryGetValue(gatheringPointId, out gatheringRoot);
 
+    public bool TryGetGatheringPointId(uint itemId, EClassJob classJobId,
+        [NotNullWhen(true)] out GatheringPointId? gatheringPointId)
+    {
+        if (classJobId == EClassJob.Miner)
+        {
+            if (_gatheringData.TryGetMinerGatheringPointByItemId(itemId, out gatheringPointId))
+                return true;
+
+            gatheringPointId = _gatheringPoints
+                .Where(x => x.Value.ExtraQuestItems.Contains(itemId))
+                .Select(x => x.Key)
+                .FirstOrDefault(x => _gatheringData.MinerGatheringPoints.Contains(x));
+            return gatheringPointId != null;
+        }
+        else if (classJobId == EClassJob.Botanist)
+        {
+            if (_gatheringData.TryGetBotanistGatheringPointByItemId(itemId, out gatheringPointId))
+                return true;
+
+            gatheringPointId = _gatheringPoints
+                .Where(x => x.Value.ExtraQuestItems.Contains(itemId))
+                .Select(x => x.Key)
+                .FirstOrDefault(x => _gatheringData.BotanistGatheringPoints.Contains(x));
+            return gatheringPointId != null;
+        }
+        else
+        {
+            gatheringPointId = null;
+            return false;
+        }
+    }
+
     public void Dispose()
     {
         _questRegistry.Reloaded -= OnReloaded;
 
     }
 
     internal sealed class DelayedGatheringExecutor(
-        GatheringData gatheringData,
         GatheringPointRegistry gatheringPointRegistry,
         TerritoryData territoryData,
         IClientState clientState,
         public IEnumerable<ITask> CreateExtraTasks()
         {
             EClassJob currentClassJob = (EClassJob)clientState.LocalPlayer!.ClassJob.RowId;
-            if (!gatheringData.TryGetGatheringPointId(Task.GatheredItem.ItemId, currentClassJob,
+            if (!gatheringPointRegistry.TryGetGatheringPointId(Task.GatheredItem.ItemId, currentClassJob,
                     out GatheringPointId? gatheringPointId))
                 throw new TaskException($"No gathering point found for item {Task.GatheredItem.ItemId}");
 
 
             .ToDictionary(x => x.ItemId, x => x.NpcId);
     }
 
-    public bool TryGetGatheringPointId(uint itemId, EClassJob classJobId,
-        [NotNullWhen(true)] out GatheringPointId? gatheringPointId)
-    {
-        if (classJobId == EClassJob.Miner)
-            return _minerGatheringPoints.TryGetValue(itemId, out gatheringPointId);
-        else if (classJobId == EClassJob.Botanist)
-            return _botanistGatheringPoints.TryGetValue(itemId, out gatheringPointId);
-        else
-        {
-            gatheringPointId = null;
-            return false;
-        }
-    }
+    public IEnumerable<GatheringPointId> MinerGatheringPoints => _minerGatheringPoints.Values;
+    public IEnumerable<GatheringPointId> BotanistGatheringPoints => _botanistGatheringPoints.Values;
+
+    public bool TryGetMinerGatheringPointByItemId(uint itemId, [NotNullWhen(true)] out GatheringPointId? gatheringPointId)
+        => _minerGatheringPoints.TryGetValue(itemId, out gatheringPointId);
+
+    public bool TryGetBotanistGatheringPointByItemId(uint itemId, [NotNullWhen(true)] out GatheringPointId? gatheringPointId)
+        => _botanistGatheringPoints.TryGetValue(itemId, out gatheringPointId);
 
     public ushort GetRecommendedCollectability(uint itemId)
         => _itemIdToCollectability.GetValueOrDefault(itemId);