clockworklabs/SpacetimeDB · error
ERROR: Skipping procedure registration '%s' because circular
Error message
ERROR: Skipping procedure registration '%s' because circular reference error is set
What it means
RegisterProcedure skips an HTTP-callable procedure registration because g_circular_ref_error is already set by a prior type-cycle detection during static module build. The procedure's static_assert on ProcedureContext is not what failed — the module-wide poison flag is. The module will subsequently fail preinit_99 validation, so the procedure never becomes callable.
Source
Thrown at crates/bindings-cpp/include/spacetimedb/internal/v10_builder.h:535
uint32_t index = static_cast<uint32_t>(is_anonymous ? (GetAnonymousViewHandlerCount() - 1) : (GetViewHandlerCount() - 1));
RawViewDefV10 view_def{
view_name,
index,
is_public,
is_anonymous,
ProductType{},
return_type,
};
UpsertView(view_def);
}
template<typename Func>
void RegisterProcedure(const std::string& procedure_name,
Func func,
const std::vector<std::string>& param_names = {}) {
if (g_circular_ref_error) {
std::fprintf(stderr, "ERROR: Skipping procedure registration '%s' because circular reference error is set\n",
procedure_name.c_str());
return;
}
using traits = function_traits<Func>;
using ReturnType = typename traits::result_type;
static_assert(traits::arity > 0, "Procedure must have at least one parameter (ProcedureContext)");
if constexpr (traits::arity > 0) {
using FirstParamType = std::remove_cv_t<std::remove_reference_t<typename traits::template arg_t<0>>>;
static_assert(std::is_same_v<FirstParamType, ProcedureContext>,
"First parameter of procedure must be ProcedureContext");
}
std::function<std::vector<uint8_t>(ProcedureContext&, BytesSource)> handler;
if constexpr (traits::arity == 1) {
handler = [func](ProcedureContext& ctx, BytesSource) -> std::vector<uint8_t> {
auto result = func(ctx);
IterBuf buf = IterBuf::take();
{View on GitHub (pinned to 524b4487d9)
Solutions
- Resolve the circular reference reported by '[CIRCULAR REFERENCE DETECTED]' earlier in the build/runtime log
- Make recursive DTOs acyclic: children become std::vector<uint64_t> or flat lists instead of nested values
- Rebuild and verify the procedure is listed in the published module
- If multiple 'Skipping ...' lines appear, they share this single root cause — fix it once
Example fix
// before — recursive DTO blocks procedure registration
struct TreeDto { std::string label; std::vector<TreeDto> kids; };
// after
struct TreeDto { std::string label; std::vector<uint32_t> kid_ids; }; Defensive patterns
Strategy: validation
Validate before calling
#include <spacetimedb/internal/module_type_registration.h>
TEST(Module, ProceduresRegistered) {
EXPECT_FALSE(SpacetimeDB::Internal::g_circular_ref_error);
} Prevention
- Flatten recursive DTOs used by procedures into ID-referencing shapes
- Smoke-test each procedure endpoint after publish
- Assert the global flag is clear in CI to catch type cycles before they hide registrations
When it happens
Trigger: An ST_PROCEDURE macro (procedure_macros.h) instantiates a registration that calls getV10Builder().RegisterProcedure('<name>', fn) in a module whose typespace also contains a recursive type — often a procedure parameter or shared DTO that contains itself via Vec/Option. The flag is set during type building, before the procedure registration runs.
Common situations: Adding a JSON/HTTP procedure whose payload struct is recursive (e.g. a tree DTO); a refactor that makes two DTOs reference each other in a module that already exposes procedures; moving types between headers so registration order changes.
Related errors
- ERROR: Skipping multi-column index registration '%s.%s' beca
- ERROR: Skipping default-value registration '%s.%s' because c
- ERROR: Skipping reducer registration '%s' because circular r
- ERROR: Skipping lifecycle reducer registration '%s' because
- ERROR: Skipping view registration '%s' because circular refe
AI-assisted analysis of clockworklabs/SpacetimeDB@524b4487d9 (2026-08-16).
Data as JSON: /api/errors/e815da6d705540e0.
Report an issue: GitHub.