xai-org/x-algorithm · error · SemanticCheckFailure
ASTNode %s expected %d arguments, %d passed.
Error message
ASTNode %s expected %d arguments, %d passed.
What it means
The unique (deduplication) kernel uses CUB's DeviceRadixSort (or DeviceSegmentedRadixSort) which requires temporary scratch memory sized by a dry-run query. The code queries temp_storage_bytes, then asks its scratch allocator for that many bytes; if the allocator returns an empty optional it throws this error, aborting the unique operation before any sorting runs.
Source
Thrown at botmaker/src/java/com/twitter/botmaker/ASTNode.java:171
return scope;
}
public static void assertChildConstant(
String exprText, ImmutableList<ASTNode> children, int index) throws SemanticCheckFailure {
ASTNode node = children.get(index);
if (!Constant.class.isAssignableFrom(node.getClass())) {
throw new SemanticCheckFailure(String.format(
"type checking expression %s failed: invalid argument type: expected a constant %s",
exprText,
node.getReturnType().toString())
);
}
}
public static void assertChildrenSize(
String exprText, ImmutableList<ASTNode> children, int expected) throws SemanticCheckFailure {
if (children.size() != expected) {
throw new SemanticCheckFailure(String.format(
"ASTNode %s expected %d arguments, %d passed.", exprText, expected, children.size()));
}
}
public static void assertChildrenSize(
String exprText, ImmutableList<ASTNode> children,
int min, int max) throws SemanticCheckFailure {
if (children.size() < min || children.size() > max) {
throw new SemanticCheckFailure(String.format(
"ASTNode %s expected %d to %d arguments, %d passed.",
exprText, min, max, children.size()));
}
}
public abstract Signature getSignature();
public abstract Extractor<E> toExtractor();View on GitHub (pinned to 24c60942c5)
Solutions
- Free or reduce other GPU allocations before calling unique (check nvidia-smi for memory headroom)
- Reduce input size (chunk the unique operation into batches) so CUB sort scratch fits the allocator budget
- Increase the scratch allocator's capacity/budget if it is configured via an environment variable or handle option
- Run on a GPU with more free memory or a device with larger total memory
- If the allocator is arena-based, ensure the arena is large enough for sort scratch, which can exceed input size for radix sort
Example fix
// before
auto d_temp = scratch_allocator.Allocate(temp_storage_bytes);
if (!d_temp) { throw std::runtime_error("unique: failed to allocate ..."); }
// after
size_t temp_storage_bytes = 0;
XAI_CUDA_CHECK(sort(nullptr, temp_storage_bytes));
// grow arena / free memory first:
scratch_allocator.Reserve(temp_storage_bytes);
auto d_temp = scratch_allocator.Allocate(temp_storage_bytes);
if (!d_temp) { throw std::runtime_error("unique: failed to allocate ..."); } Defensive patterns
Strategy: fallback
Validate before calling
// Estimate CUB sort scratch before calling unique:
// radix sort temp is roughly 2 * input bytes + counters; be conservative.
size_t estimated = 2 * static_cast<size_t>(n) * sizeof(KeyT) + (1 << 20);
size_t free = 0, total = 0;
cudaMemGetInfo(&free, &total);
if (estimated > free) {
// chunk the input or free memory first
} Type guard
bool can_allocate_scratch(ScratchAllocator& alloc, size_t bytes) {
auto probe = alloc.Allocate(bytes);
return probe.has_value(); // RAII: probe frees on scope exit if pooled
} Try / catch
try {
run_unique(keys, n, scratch_allocator);
} catch (const std::runtime_error& e) {
if (std::string(e.what()).find("sort scratch") != std::string::npos) {
// retry with chunked input or after freeing GPU memory
run_unique_chunked(keys, n, chunk_size, scratch_allocator);
} else {
throw;
}
} Prevention
- Monitor free GPU memory (cudaMemGetInfo) before sort-heavy unique ops
- Size scratch arenas for worst-case input, not average
- Chunk large inputs so per-chunk temporaries stay small
- Avoid running multiple scratch-consuming ops concurrently on one allocator
When it happens
Trigger: Calling the unique op on a very large input so the CUB sort needs more scratch than the allocator's budget/cap allows; a scratch allocator backed by a pre-allocated arena or memory pool that is exhausted; a CUDA context where cudaMalloc under the hood fails (other allocations consuming GPU memory); or a zero/oversized temp_storage_bytes path interacting badly with allocator limits.
Common situations: Large ragged tensors causing huge sort scratch requirements, memory fragmentation in a long-running process, running multiple CUDA ops concurrently that share a fixed scratch pool, or GPU memory pressure from other jobs on the same device.
Related errors
- type checking expression %s failed: expects %d arguments, %d
- Only int32 is supported for unique.
- Only 1D arrays are supported for unique.
- type checking expression %s failed: invalid argument type: e
- ASTNode %s expected %d to %d arguments, %d passed.
AI-assisted analysis of xai-org/x-algorithm@24c60942c5 (2026-08-28).
Data as JSON: /api/errors/f7348d8e4b7b7359.
Report an issue: GitHub.