Inconsisten Ledge climbing system

Hi! I’m creating a system where you can climb/vault over high walls (kinda like gta).
I have put together a system that works great the first time its run… however after the first climb it becomes very inconsistent and it almost always fails.

local script inside of startercharacterscripts

local player = game.Players.LocalPlayer
local character = player.Character
local humanoid = character:WaitForChild("Humanoid")
local rootPart = character:WaitForChild("HumanoidRootPart")
local head = character:WaitForChild("Head")

local climbAnim = humanoid:LoadAnimation(script:WaitForChild("Climb"))

--vaulting
local raycastParams = RaycastParams.new()
raycastParams.FilterDescendantsInstances = {character}
raycastParams.FilterType = Enum.RaycastFilterType.Exclude

local canVault = true
local ledgePart = nil

local UIS = game:GetService("UserInputService")

local pressed = 0 

local function partCheck(ledge)
	local vaultPartCheck = workspace:Raycast(ledge.Position + Vector3.new(0, -1, 0) + ledge.LookVector * 1, ledge.UpVector * 3, raycastParams)
	if vaultPartCheck == nil then
		return true
	else
		return false
	end
end

local function detectLedge()
	if (humanoid:GetState() == Enum.HumanoidStateType.Freefall or humanoid:GetState() == Enum.HumanoidStateType.Jumping) then
		local vaultCheck = workspace:Raycast(rootPart.CFrame.Position, rootPart.CFrame.LookVector * 5, raycastParams)
		if vaultCheck then
			if vaultCheck.Instance then			
				local localPos = vaultCheck.Instance.CFrame:PointToObjectSpace(vaultCheck.Position)
				local localLedgePos = Vector3.new(localPos.X, vaultCheck.Instance.Size.Y/2, localPos.Z)
				local ledgePos = vaultCheck.Instance.CFrame:PointToWorldSpace(localLedgePos)
				local ledgeOffset = CFrame.lookAt(ledgePos, ledgePos - vaultCheck.Normal)

				local magnitude = (ledgePos - head.Position).Magnitude
				if magnitude < 4 then
					if partCheck(ledgeOffset) then
						



						
						ledgePart = Instance.new("Part")
						ledgePart.Parent = workspace
						ledgePart.Anchored = true
						ledgePart.Size = Vector3.one
						ledgePart.CFrame = ledgeOffset + Vector3.new(0, -2, 0) + ledgeOffset.LookVector * -1
						ledgePart.CanQuery = false
						ledgePart.CanCollide = false
						ledgePart.CanTouch = false
						ledgePart.Transparency = 1


						climbAnim:Play()
						rootPart.Anchored = true
						humanoid.AutoRotate = false -- so shift lock doesnt't rotate character
						rootPart.CFrame = rootPart.CFrame:Lerp(CFrame.lookAt(ledgePart.Position, (ledgePart.CFrame * CFrame.new(0, 0, -1)).Position), .25)
						climbAnim.Stopped:Wait()
						rootPart.Anchored = false
						character:MoveTo(Vector3.new(rootPart.Position.X, vaultCheck.Instance.Position.Y + vaultCheck.Instance.Size.Y*0.5 + 0.2, rootPart.Position.Z))
						humanoid.AutoRotate = true
						ledgePart:Destroy()
					end
				end
			end
		end
	end	

end

UIS.InputBegan:Connect(function(input)
	if input.KeyCode == Enum.KeyCode.Space then
		if tick() - pressed < 0.2 and tick() - pressed > 0 then
			detectLedge()
		end
		pressed = tick()
	end
end)

first climb - Roblox Studio (gyazo.com)
second climb - Roblox Studio (gyazo.com)

I have also noticed that server sided the player is weirdly aligned to the middle of the ledge.

So far ive tried making the entire aligment and raycast serversided but that did nothing but make the system slower.

Any help is much appreciated!

Bump! Still haven’t found the issue, I tried modifying the ray-cast with no succes