Can’t help you much without seeing your KnitServer script, but I’m guessing you’re not adding the service before AbilityHandler gets called. Here’s an example Service script that’s correctly set up:
local Knit = require(game:GetService("ReplicatedStorage").Packages.Knit)
local AbilityService = Knit.CreateService {
Name = "AbilityService ";
Client = {
ClientEvent = Knit.CreateSignal(); -- Create the signal
};
}
function AbilityService :AbilityHandler(player)
print("Adding...")
self.Client.ClientEvent:Fire(player)
print("... success!")
end
return AbilityService
Here’s an example KnitServer script that will throw the error you mentioned even though the Service itself is set up correctly:
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local ServerStorage = game:GetService("ServerStorage")
local Knit = require(ReplicatedStorage.Packages.Knit)
Knit.AddServices(ServerStorage.Services)
game.Players.PlayerAdded:Connect(function(player)
require(ServerStorage.Services.AbilityService ):AbilityHandler(player, 10)
end)
--Ensure Knit starts *after* PlayerAdded callback calls AbilityHandler
game.Players.PlayerAdded:Wait()
wait()
Knit.Start():andThen(function()
print("Knit started server")
end)
Aaaand here’s how to fix that:
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local ServerStorage = game:GetService("ServerStorage")
local Knit = require(ReplicatedStorage.Packages.Knit)
Knit.AddServices(ServerStorage.Services)
Knit.Start():andThen(function()
print("Knit started server")
end)
game.Players.PlayerAdded:Connect(function(player)
require(ServerStorage.Services.AbilityService):AbilityHandler(player, 10)
end)
The broken one is just like a normal KnitServer script, except it calls AbilityHandler before Knit is Started. This makes sense if you look at the source code for KnitServer:
--..inside KnitServer.Start
-- Bind remotes:
for _,service in pairs(services) do
local middleware = service.Middleware or {}
local inbound = middleware.Inbound or knitMiddleware.Inbound
local outbound = middleware.Outbound or knitMiddleware.Outbound
service.Middleware = nil
for k,v in pairs(service.Client) do
if type(v) == "function" then
service.KnitComm:WrapMethod(service.Client, k, inbound, outbound)
elseif v == SIGNAL_MARKER then
service.Client[k] = service.KnitComm:CreateSignal(k, inbound, outbound)
elseif type(v) == "table" and v[1] == PROPERTY_MARKER then
service.Client[k] = service.KnitComm:CreateProperty(k, v[2], inbound, outbound)
end
end
end
You can see that it calls KnitComm:CreateSignal on the signal you passed and assigns the return value to the key that the signal was previously at, so Service.Client.ClientEvent is a completely different thing after KnitStart. Knit.CreateSignal doesn’t actually return a signal that you can call Fire on, it has to be processed by Knit.Start first.
In short, start Knit *before using any Service". This is also how the examples work, although I haven’t spotted anywhere that they explicitly call it out.