Problems with bindable events

The current thread cannot fire 'ServerLoaded' - the target has additional capabilities: LoadUnownedAsset (and 3 more). < the error

The code that tried to fire the bindable event is located in ServerScriptService > Script > ModuleScript.

function module:Initialise()
	shared.SERVER_LOADED = false
	
	shared.MODULES = SERVER_SCRIPT_SERVICE.ServerModules
	shared.CLASSES = SERVER_SCRIPT_SERVICE.Classes
	shared.REPLICATED_MODULES = REPLICATED_STORAGE.ReplicatedModules

	shared.REMOTES = REPLICATED_STORAGE.Remotes
	shared.BINDABLES = REPLICATED_STORAGE.Bindables
	
	shared.LOADED = shared.BINDABLES.ServerLoaded
	
	module:InitialiseChildren(shared.CLASSES)
	module:InitialiseChildren(shared.MODULES)
	module:InitialiseChildren(shared.REPLICATED_MODULES)
	
	shared.SERVER_LOADED = true
	shared.LOADED:Fire() --<<<<< HERE
	
	print("Done")
end

The bindable event itself is located in ReplicatedStorage > Folder > BindableEvent

I think it might be worth noting that the same idea is done for the client side, except the client scripts are inside ReplicatedStorage rather than ServerScriptService, and that works completely fine.

What is happening? I’ve tried to search up on some new feature called ‘Script Capabilities’ which I believe is causing this error, but I’ve failed to solve my problem

1 Like

@FreedomSlows The error comes exactly from what you suspected: Script Capabilities, a security feature introduced by Roblox.

Why this happens
Scripts in ServerScriptService have a restricted set of capabilities by default. Meanwhile, a BindableEvent located in ReplicatedStorage inherits additional capabilities (including LoadUnownedAsset and three others mentioned in the error) because ReplicatedStorage is accessible to both the client and the server.

Roblox blocks Fire() because the calling thread (your script in ServerScriptService) does not have all the required capabilities for the target (the BindableEvent in ReplicatedStorage).

That’s exactly why it works on the client side: your client scripts are in ReplicatedStorage, so they share the same capabilities as the BindableEvent. No conflict there.


Solutions

Solution 1 — Move the BindableEvent to ServerStorage (recommended)
This is the logical fix. A BindableEvent named ServerLoaded has no reason to be in ReplicatedStorage since the client doesn’t need it.

ServerStorage
└── Bindables
└── ServerLoaded

ReplicatedStorage
└── Bindables
└── ClientLoaded (this one stays here, which is correct)

Your code becomes:

local SERVER_STORAGE = game:GetService(“ServerStorage”)
– Inside Initialise()
shared.LOADED = SERVER_STORAGE.Bindables.ServerLoaded
shared.LOADED:Fire() – Works, same capability context


Solution 2 — Move the Script into ReplicatedStorage
Like your client scripts, you could place your server script in ReplicatedStorage to match capabilities. But this is not recommended: server logic does not belong in ReplicatedStorage. It’s bad architecture and a security risk.


Solution 3 — Use a BindableEvent created dynamically on the server
If you absolutely need ServerLoaded to remain in ReplicatedStorage (so the client can also listen to it), create the BindableEvent in code instead of placing it manually in the hierarchy:

– On the server, you create the event yourself
local serverLoadedEvent = Instance.new(“BindableEvent”)
serverLoadedEvent.Name = “ServerLoaded”
serverLoadedEvent.Parent = game.ReplicatedStorage.Bindables
shared.LOADED = serverLoadedEvent
shared.LOADED:Fire() – The script is the owner, no capability conflict

But be careful: if the client needs to listen to ServerLoaded, a RemoteEvent is a much better choice than a BindableEvent in ReplicatedStorage.


Final recommendation

Solution 1 is the correct one. The rule to remember:

BindableEvent = server ↔ server or client ↔ client communication → place it where the scripts that use it live

RemoteEvent = server ↔ client communication → ReplicatedStorage is correct

ServerLoaded is a purely server-side signal, so ServerStorage is its natural home.

1 Like