xai-org/x-algorithm · error · std::invalid_argument

XAI_ASYNC_EMB_TIMEOUT_SECONDS must be a positive integer

Error message

XAI_ASYNC_EMB_TIMEOUT_SECONDS must be a positive integer

What it means

XAI_ASYNC_EMB_TIMEOUT_SECONDS is parsed with strtol and must be a strictly positive integer with no trailing characters. If it is unset the code falls back to a 1800-second watchdog, so this error only fires when the variable exists but is malformed (empty, zero, negative, fractional, or containing non-numeric suffixes).

Source

Thrown at phoenix/xrex/cuda/async_emb/src/async_emb_comm.cc:68

void requireEnvironment(const char* name, const char* expected) {
  const char* value = std::getenv(name);
  if (value == nullptr || std::strcmp(value, expected) != 0) {
    throw std::runtime_error(
        "async_emb requires " + std::string(name) + "=" + expected + " before process startup"
    );
  }
}

std::chrono::seconds watchdogTimeout() {
  const char* value = std::getenv("XAI_ASYNC_EMB_TIMEOUT_SECONDS");
  if (value == nullptr) {
    return std::chrono::seconds(1800);
  }
  char* end = nullptr;
  long seconds = std::strtol(value, &end, 10);
  if (end == value || *end != '\0' || seconds <= 0) {
    throw std::invalid_argument("XAI_ASYNC_EMB_TIMEOUT_SECONDS must be a positive integer");
  }
  return std::chrono::seconds(seconds);
}

std::once_flag warmup_once;

void warmupKernels(int8_t* scratch, cudaStream_t stream) {
  auto* bf16 = reinterpret_cast<__nv_bfloat16*>(scratch);
  auto* f32 = reinterpret_cast<float*>(scratch);
  auto* i32 = reinterpret_cast<int32_t*>(scratch);
  const SliceLayout slices{0, 8, 1};
  launch_lookup_dispatch(i32, bf16, bf16, slices, 1, stream);
  launch_grad_dispatch(bf16, bf16, slices, stream);
  launch_grad_segment_sum(bf16, i32, f32, f32, slices, 0, stream);
  launch_lookup_combine(bf16, bf16, slices, stream);
  XAI_CUDA_CHECK(cudaStreamSynchronize(stream));
}

View on GitHub (pinned to 24c60942c5)

Solutions

  1. Export a plain positive integer: export XAI_ASYNC_EMB_TIMEOUT_SECONDS=1800.
  2. Remove quotes/units/whitespace from the value in your job spec or .env file.
  3. If you do not need a custom timeout, unset the variable to use the 1800s default.

Example fix

# before
export XAI_ASYNC_EMB_TIMEOUT_SECONDS="30m"

# after
export XAI_ASYNC_EMB_TIMEOUT_SECONDS=1800
Defensive patterns

Strategy: validation

Validate before calling

const char* v = std::getenv("XAI_ASYNC_EMB_TIMEOUT_SECONDS");
if (v) {
    char* end = nullptr;
    long n = std::strtol(v, &end, 10);
    if (end == v || *end != '\0' || n <= 0)
        throw std::runtime_error("XAI_ASYNC_EMB_TIMEOUT_SECONDS must be a positive integer");
}

Prevention

When it happens

Trigger: Setting XAI_ASYNC_EMB_TIMEOUT_SECONDS to values like "", "0", "-5", "30s", "1.5", or "1800 " while constructing AsyncEmbContext (watchdogTimeout is called from the constructor).

Common situations: Kubernetes manifests quoting the value ("1800" is fine but "30s" from a duration convention is not), CI templates appending units, copy-paste from docs of a different timeout variable that accepts durations.

Understand the failure class

Related errors


AI-assisted analysis of xai-org/x-algorithm@24c60942c5 (2026-08-28). Data as JSON: /api/errors/45466dc602dadd21. Report an issue: GitHub.