jax-ml/jax · error · RuntimeError

Profile has already been started. Only one profile may be ru

Error message

Profile has already been started. Only one profile may be run at a time.

What it means

jax.profiler.start_trace raises RuntimeError if a profiling session is already active — only one trace may run at a time per process, enforced via `_profile_state.profile_session`.

Source

Thrown at jax/_src/profiler.py:185

  Only one trace may be collected at a time. A RuntimeError will be raised if
  :func:`start_trace` is called while another trace is running.

  Args:
    log_dir: The directory to save the profiler trace to (usually the
      TensorBoard log directory).
    create_perfetto_link: A boolean which, if true, creates and prints link to
      the Perfetto trace viewer UI (https://ui.perfetto.dev). The program will
      block until the link is opened and Perfetto loads the trace.
    create_perfetto_trace: A boolean which, if true, additionally dumps a
      ``perfetto_trace.json.gz`` file that is compatible for upload with the
      Perfetto trace viewer UI (https://ui.perfetto.dev). The file will also be
      generated if ``create_perfetto_link`` is true. This could be useful if you
      want to generate a Perfetto-compatible trace without blocking the process.
    profiler_options: Profiler options to configure the profiler for collection.
  """
  with _profile_state.lock:
    if _profile_state.profile_session is not None:
      raise RuntimeError("Profile has already been started. "
                         "Only one profile may be run at a time.")
    clear_metadata()
    # Make sure backends are initialized before creating a profiler
    # session. Otherwise on Cloud TPU, libtpu may not be initialized before
    # creating the tracer, which will cause the TPU tracer initialization to
    # fail and no TPU operations will be included in the profile.
    xla_bridge.get_backend()

    options = profiler_options
    if options is None:
      options = ProfileOptions()
    set_metadata("jax_version", jax_version_module.__version__)
    jaxlib_version_str = ".".join(map(str, version_lib))
    set_metadata("jaxlib_version", jaxlib_version_str)
    for backend_name in xla_bridge.backends():
      try:
        backend = xla_bridge.get_backend(backend_name)
        set_metadata(f"{backend.platform}_version", backend.platform_version)

View on GitHub (pinned to 1e1c6a8fc0)

Solutions

  1. Always pair start_trace with stop_trace (prefer the `jax.profiler.trace()` context manager)
  2. Call stop_trace before starting a new trace
  3. Add locking/flags around programmatic profiling in multi-threaded code

Example fix

# before
jax.profiler.start_trace('/tmp/t1')
jax.profiler.start_trace('/tmp/t2')  # RuntimeError
# after
with jax.profiler.trace('/tmp/t1'):
  run_model()
Defensive patterns

Strategy: try-catch

Try / catch

try:
    jax.profiler.start_trace(log_dir)
except RuntimeError as e:
    if 'already been started' in str(e):
        jax.profiler.stop_trace()
        jax.profiler.start_trace(log_dir)
    else:
        raise

Prevention

When it happens

Trigger: Nested or overlapping `start_trace` calls: calling start_trace twice without stop_trace, or concurrent threads starting traces; the `trace` context manager used re-entrantly.

Common situations: Repeated notebook cells; concurrent profiling from multiple libraries; forgetting stop_trace after an exception bypassed the context manager.

Related errors


AI-assisted analysis of jax-ml/jax@1e1c6a8fc0 (2026-08-27). Data as JSON: /api/errors/102f55efdd04b6a6. Report an issue: GitHub.