ProfileService not finding player profile

hello! i’m new to using profileservice (literally just started using it yesterday) and i’ve hit a bit of a roadblock—my code that fetches the data profile of a player when updating/setting/getting is erroring, saying that the profile doesn’t exist for the player in question. on paper it should work, but i’m not sure where I’m going wrong
image
ModuleScript code (handles the basic profileservice functions and setup)

ModuleScript
local PlayerDataHandler = {}

local ProfileService = require(game.ServerScriptService.ProfileService)
local Players = game:GetService("Players")

local DataTemplate = {
    Cash = 0,
    Position = {
        X = 0,
        Y = 0,
        Z = 0
    },
    Inventory = {}
}

local ProfileStore = ProfileService.GetProfileStore(
    "PlayerProfile",
    DataTemplate
)

local Profiles = {}

local function onPlayerAdded(player : Player)
    local profile = ProfileStore:LoadProfileAsync(`Player_{player.UserId}`) -- Gets the profile of the player who joins
    if profile then 
        profile:AddUserId(player.UserId) -- Adds user ID to profile 
        profile:Reconcile() -- Adds missing variables from DataTemplate to the profile 
        
        profile:ListenToRelease(function()
            Profiles[player] = nil -- On :Release(), set the profile of the character to nil
            
            player:Kick()
        end)
        
        if not player:IsDescendantOf(Players) then 
            profile:Release()
        else
            Profiles[player] = profile 
            
            print(`Successfully loaded player {player}'s data`)
            print(Profiles[player].Data)
        end
    else 
        player:Kick()
    end
end

local function onPlayerRemoved(player : Player)
    if Profiles[player] then 
        Profiles[player]:Release()
    end
end

function PlayerDataHandler:Init()
    for _, player in Players:GetPlayers() do 
        task.spawn(onPlayerAdded, player)
    end
    
    Players.PlayerAdded:Connect(onPlayerAdded)
    
    Players.PlayerRemoving:Connect(onPlayerRemoved)
end

local function getProfile(player : Player)
    assert(Profiles[player], `Profile does not exist for {player.UserId}`)
    
    return Profiles[player]
end

-- Getter/Setter methods

function PlayerDataHandler:GetKey(player : player, key)
    -- If there's no data for the corresponding key, throw error
    local profile = getProfile(player)
    assert(profile.Data[key], `Data does not exist for key {key}`)
    
    return profile.Data[key]
end

function PlayerDataHandler:SetKey(player : player, key, value)
    -- If there's no data for the corresponding key, throw error
    local profile = getProfile(player)
    assert(profile.Data[key], `Data does not exist for key {key}`)
    
    -- If the type of value we want to set does not match the type of the key, throw error
    assert(type(profile.Data[key]) == type(value), `New key type does not match type of old key {key}`)
    
    profile.Data[key] = value
end

function PlayerDataHandler:Update(player : player, key, callback)
    local profile = getProfile(player)
    
    local oldData = self:GetKey(player, key)
    local newData = callback(oldData) -- Gives the old data as a parameter into the callback function
    
    self:SetKey(player, key, newData)
end

return PlayerDataHandler

and here’s the script that’s writing to the data profile, my goal is to save the character’s position when they leave and load it when they join back

PositionSave
local PlayerDataHandler = require(game.ServerScriptService.PlayerDataHandler)
local Players = game:GetService("Players")

PlayerDataHandler:Init()

local function saveCharacterPosition(player : Player)
    local character = player.Character or player.CharacterAdded:Wait()
    local humanoidRootPart : Part = character:WaitForChild("HumanoidRootPart")
    
    PlayerDataHandler:Update(player, "Position", function(savedPosition)
        local newPosition : Vector3 = humanoidRootPart.Position
        
        for coordinate, value in savedPosition do
            -- Iterate over every currently saved coordinate and write the corresponding new coordinate's value to it 
            coordinate[value] = newPosition[coordinate] 
        end
        
        print(`Saved new position: {newPosition["X"]}, {newPosition["Y"]}, {newPosition["Z"]}`)
        
        return savedPosition
    end)
end

local function loadCharacterPosition(player : Player)
    local character = player.Character or player.CharacterAdded:Wait()
    local humanoidRootPart : Part = character:WaitForChild("HumanoidRootPart")
    local savedPosition = PlayerDataHandler:GetKey(player, "Position")
    
    humanoidRootPart.Position = Vector3.new(savedPosition.X, savedPosition.Y, savedPosition.Z)
    print(`Loaded player {player} at position {savedPosition}`)
end

Players.PlayerRemoving:Connect(saveCharacterPosition)

Players.PlayerAdded:Connect(loadCharacterPosition)

thanks in advance!