Self-hosted pool worker never receives dispatch — cloud run stuck at CREATING, worker gets heartbeats only

Where does the bug appear (feature/product)?

Cursor SDK

Describe the Bug

A cloud agent created via @cursor/sdk against a self-hosted pool worker is
created successfully and reported as running/CREATING, but the run is never
dispatched to the connected, idle, label-matching worker
. The worker stays
idle and receives only heartbeat frames — never a task-dispatch frame. The run
sits at CREATING indefinitely until it is abandoned.

The worker is healthy, connected, visible in GET /v0/private-workers, and its
backend workerId matches the id the worker reports on connect — so this is not
a “worker not registered” problem.

  • Agent.create + agent.send succeed; a run is returned.
  • The run’s status is running/CREATING but never advances.
  • The worker never becomes “in use”; GET /v0/private-workers shows isInUse: false the entire time.
  • On the web UI the run reports “Waiting for self-hosted worker: No self-hosted worker matches the requested labels”.

Steps to Reproduce

1. Start a self-hosted pool worker

agent worker start --pool \
  --pool-name my-pool \
  --worker-dir ./repo \
  --management-addr ":8080" \
  --verbose
# Registering to worker pool
#   Repo: <org>/<repo>
#   Pool: my-pool
# Received frame meta={frameCount: 1}   <- heartbeats only from here on

2. Create a cloud agent targeting that pool via the SDK (from any other
machine/process using the same account/API key):

import { Agent } from "@cursor/sdk";

const agent = await Agent.create({
  apiKey: process.env.CURSOR_API_KEY,
  model: "composer-2.5",
  cloud: {
    repos: [{ url: "https://gitlab.com/<org>/<repo>", startingRef: "main" }],
    env: { type: "pool", name: "my-pool" },
  },
});

const run = await agent.send("reply OK");
console.log(agent.agentId, run.id);

3. Observe — the run stays at CREATING and the worker is never dispatched:

# Worker is registered and idle, backend id == worker's self-reported id:
curl -s https://api.cursor.com/v0/private-workers \
  -H "Authorization: Bearer $CURSOR_API_KEY"
# { "workers": [ { "workerId": "...", "repoUrl": "https://gitlab.com/<org>/<repo>",
#                  "isInUse": false } ] }

# Run never advances past CREATING; note the repoUrl has NO scheme:
curl -s https://api.cursor.com/v1/agents/<agentId>/runs/<runId> \
  -H "Authorization: Bearer $CURSOR_API_KEY"
# { "status": "CREATING",
#   "git": { "branches": [ { "repoUrl": "gitlab.com/<org>/<repo>" } ] } }

Operating System

Linux

Version Information

  • @cursor/sdk: 1.0.20
  • Worker CLI (agent): 2026.07.23-e383d2b (installed via curl https://cursor.com/install)
  • Worker: self-hosted pool worker (agent worker start --pool --pool-name <pool> --worker-dir <dir> --labels-file <file>)
  • Git remote of the worker checkout: https://gitlab.com/<org>/<repo>.git
  • Run creation: Agent.create({ cloud: { repos: [{ url: "https://gitlab.com/<org>/<repo>", startingRef: "main" }], env: { type: "pool", name: "<pool>" } } }) then agent.send(...)

This worked previously and started failing recently

For AI issues: which model did you use?

composer-2.5

Additional Information

Example runs
• Agent: bc-fd93adad-732a-4f22-85e9-1b29282f4e7f
• Run: run-c258da1a-d497-48aa-9a49-12e8703a3692
• Worker: ee307ce8-554e-4578-beba-9a3a70589768

Does this stop you from using Cursor

Yes - Cursor is unusable

+1

Having the same issue, the web UI reports:
`Waiting for self-hosted worker: No self-hosted worker matches the requested labels (attempt 16/40)`

Making Cursor Cloud agents unusable for us.

Hey there!

Your setup looks correct - this wasn’t a misconfigured worker or pool labels on your side. We had a short-lived routing issue on Aug 4 where self-hosted pool runs (including SDK env.type: "pool") couldn’t match connected workers and stayed stuck at CREATING with that “No self-hosted worker matches the requested labels” message.

That issue has been addressed on our side. Could you start a fresh run with the same SDK call and confirm whether it dispatches now? If it still sticks, share the new agent / run IDs and we’ll dig in.