How to Fix 'RuntimeError: CUDA error: CUBLAS_STATUS_ALLOC_FAILED when calling cublasCreate(handle)' in PyTorch on Linux

How to Fix 'RuntimeError: CUDA error: CUBLAS_STATUS_ALLOC_FAILED when calling cublasCreate(handle)' in PyTorch on Linux

To resolve RuntimeError: CUDA error: CUBLAS_STATUS_ALLOC_FAILED when calling cublasCreate(handle) immediately, kill orphaned GPU processes holding CUDA contexts and enable PyTorch expandable memory segments:

That stalls the pipeline. Execution halts immediately.

# 1. Terminate orphaned processes holding GPU hardware handles
sudo fuser -v /dev/nvidia* -k || true

# 2. Configure PyTorch memory allocator to eliminate virtual address fragmentation
export PYTORCH_CUDA_ALLOC_CONF="expandable_segments:True,max_split_size_mb:128"

# 3. If running inside Docker, ensure host IPC or increased shared memory
docker run --gpus all --ipc=host --shm-size=16g ...

In your Python code, clear existing cached allocations and explicitly initialize CUDA before fork-based multiprocessing:

import torch

if torch.cuda.is_available():
    torch.cuda.empty_cache()
    # Force early cuBLAS handle creation on device 0 to surface context errors immediately
    torch.cuda.init()

Why This Error Occurs: cuBLAS Context vs VRAM Exhaustion

The error CUBLAS_STATUS_ALLOC_FAILED does not mean the NVIDIA Basic Linear Algebra Subprograms (cuBLAS) library is corrupted. It occurs when PyTorch requests a hardware context handle via cublasCreate_v2(&handle), but the CUDA driver fails to allocate the internal workspace memory buffer (typically 16 MB to 64 MB of contiguous device memory) required to initialize the cuBLAS state machine.

This failure stems from three distinct root causes on Linux:

  1. Undetected Zombie VRAM Allocation: A previous training job, Jupyter kernel, or vLLM instance crashed without releasing GPU memory. While nvidia-smi might show high utilization without listing PIDs under Compute Processes, the underlying /dev/nvidia* device nodes remain locked.
  2. Virtual Address Space Fragmentation: PyTorch pre-allocates large memory blocks via its caching allocator (cudaMalloc). When a linear algebra operation (such as torch.matmul, nn.Linear, or attention projection) triggers cublasCreate(), the GPU may have physical VRAM left, but lacks a contiguous virtual address block for the cuBLAS workspace.
  3. Container IPC and Shared Memory Depletion: Docker containers default to 64 MB of shared memory (/dev/shm). When PyTorch DataLoader workers or CUDA IPC mechanisms attempt inter-process tensor transfers, memory allocation primitives fail silently, causing subsequent cuBLAS initialization calls to abort with ALLOC_FAILED.
Trigger Scenario Symptoms in Logs Primary Fix
Orphaned CUDA Processes nvidia-smi shows memory consumed, empty PID table fuser -v /dev/nvidia* -k
Allocator Address Fragmentation Crash occurs after several training iterations PYTORCH_CUDA_ALLOC_CONF="expandable_segments:True"
Docker /dev/shm Exhaustion Crash occurs when num_workers > 0 --ipc=host --shm-size=16g
Linux ulimit Lock Limits cudaErrorMemoryAllocation in system journal ulimit -l unlimited
CUDA Driver Version Mismatch Crash occurs immediately on torch.cuda.init() Match pip torch wheel with system CUDA driver

Step-by-Step Resolution

Step 1: Detect and Purge Hidden GPU Processes

Check for processes holding GPU file descriptors that do not appear in the standard nvidia-smi compute table:

# Query active processes on all NVIDIA character device nodes
sudo fuser -v /dev/nvidia*

If zombie PIDs appear in the output, terminate them immediately:

# Force-kill all processes attached to NVIDIA devices
sudo fuser -v /dev/nvidia* -k

# Verify the GPU memory returns to 0 MiB baseline
nvidia-smi --query-gpu=memory.used,memory.total --format=csv,noheader,nounits

Step 2: Configure PyTorch Memory Allocator Flags

PyTorch 2.0 and later provides the expandable_segments allocator flag. This feature uses virtual memory management APIs (cuMemCreate and cuMemMap) to allocate physical memory pages without requiring large contiguous virtual address ranges.

Add these environment variables to your shell environment or application launcher script:

# Add to ~/.bashrc or container startup script
export PYTORCH_CUDA_ALLOC_CONF="expandable_segments:True,max_split_size_mb:128"
export CUDA_MODULE_LOADING="LAZY"

Apply the changes:

source ~/.bashrc

Step 3: Fix Docker and Container IPC Permissions

If your training workload runs inside Docker, Kubernetes, or Apptainer, the default /dev/shm size of 64 MB causes CUDA IPC failures that manifest as cuBLAS allocation errors.

Always pass --ipc=host or configure explicit shared memory sizes:

# Launch Docker with host IPC and expanded shared memory
docker run --gpus all \
  --ipc=host \
  --shm-size=16g \
  --ulimit memlock=-1:-1 \
  --ulimit stack=67108864 \
  -it my-pytorch-image:latest

In Kubernetes Pod specifications, mount an emptyDir backed by memory for /dev/shm:

spec:
  containers:
  - name: pytorch-worker
    image: my-pytorch-image:latest
    volumeMounts:
    - mountPath: /dev/shm
      name: dshm
    resources:
      limits:
        nvidia.com/gpu: 1
  volumes:
  - name: dshm
    emptyDir:
      medium: Memory
      sizeLimit: 16Gi

Step 4: Handle Multiprocessing Start Methods in Python

When using Python’s multiprocessing library with CUDA, the default fork start method copies the parent process’s memory space without duplicating CUDA driver contexts. This corrupts the cuBLAS internal state and triggers CUBLAS_STATUS_ALLOC_FAILED.

Enforce spawn at the very beginning of your entrypoint script:

import torch
import torch.multiprocessing as mp

if __name__ == "__main__":
    # Must be set before any torch.cuda operations
    mp.set_start_method("spawn", force=True)
    
    device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
    
    # Test cuBLAS initialization cleanly
    a = torch.randn(512, 512, device=device)
    b = torch.randn(512, 512, device=device)
    c = torch.matmul(a, b)
    print(f"cuBLAS initialized successfully. Matrix shape: {c.shape}")

Step 5: Check Linux System Locked Memory Limits

CUDA pinned memory requires high operating system limits for locked memory (memlock). If systemd or PAM restricts locked memory, cuBLAS cannot pin pages for high-speed DMA transfers.

Inspect your current limits:

ulimit -l

If the command returns a small number (such as 64 or 16384), increase the limits in /etc/security/limits.conf:

sudo tee -a /etc/security/limits.conf << 'EOF'
* soft memlock unlimited
* hard memlock unlimited
EOF

Restart your terminal session to apply the new system limits.

Verification Checklist

Run this standalone diagnostic script to verify that cuBLAS handle allocation and high-throughput matrix multiplications execute without errors:

python3 -c "
import torch

print(f'PyTorch Version: {torch.__version__}')
print(f'CUDA Available: {torch.cuda.is_available()}')

if torch.cuda.is_available():
    device = torch.cuda.current_device()
    props = torch.cuda.get_device_properties(device)
    print(f'Active Device: {props.name} (Compute {props.major}.{props.minor})')
    print(f'Free VRAM: {torch.cuda.mem_get_info()[0] / (1024**3):.2f} GB')
    
    # Stress test cuBLAS allocation across 5 matrix multiplications
    for i in range(5):
        x = torch.randn(2048, 2048, device='cuda', dtype=torch.float16)
        y = torch.matmul(x, x)
        torch.cuda.synchronize()
        print(f'Iteration {i+1}: cuBLAS MatMul OK')
        
    print('VERIFICATION PASSED: cuBLAS handle created and functional.')
"

If all 5 iterations report cuBLAS MatMul OK followed by VERIFICATION PASSED, your Linux environment is clean and ready for production workloads.

Official Documentation & Primary References

BC

Written by B. Cho

Lead AI Systems & Linux Infrastructure Engineer

Specializing in GPU inference engines (vLLM, SGLang, Ollama), CUDA memory allocation, and Model Context Protocol (MCP) infrastructure on Linux workstations.