cockroachdb/cockroach · error · Error

Unable to retrieve the Jobs table.

Error message

Unable to retrieve the Jobs table.

What it means

getJobs in db-console wraps timeoutFetch of `_admin/jobs?status=&type=&limit=`; when the fetch exceeds its deadline, the TimeoutError is converted to this fixed message (jobsTimeoutErrorMessage = 'Unable to retrieve the Jobs table.') while the URL and request are console.error'd. Non-timeout errors propagate unchanged, so seeing this exact string means the admin jobs RPC was too slow, not failed.

Source

Thrown at pkg/ui/workspaces/db-console/src/util/api.ts:415

export const jobsTimeoutErrorMessage = "Unable to retrieve the Jobs table.";

export function getJobs(
  req: JobsRequestMessage,
  timeout?: moment.Duration,
): Promise<JobsResponseMessage> {
  const url = `${API_PREFIX}/jobs?status=${req.status}&type=${req.type}&limit=${req.limit}`;
  return timeoutFetch(serverpb.JobsResponse, url, null, timeout).then(
    // eslint-disable-next-line @typescript-eslint/ban-ts-comment
    // @ts-ignore
    (response: JobsResponseMessage) => response,
    (err: Error) => {
      if (err instanceof TimeoutError) {
        // eslint-disable-next-line no-console
        console.error(
          `Jobs page time out because attempt to retrieve jobs exceeded ${err.timeout.asMilliseconds()}ms.`,
          `URL: ${url}. Request: ${JSON.stringify(req)}`,
        );
        throw new Error(jobsTimeoutErrorMessage);
      } else {
        throw err;
      }
    },
  );
}

export function getJob(
  req: JobRequestMessage,
  timeout?: moment.Duration,
): Promise<JobResponseMessage> {
  return timeoutFetch(
    serverpb.JobResponse,
    `${API_PREFIX}/jobs/${req.job_id}`,
    null,
    timeout,
  );
}

View on GitHub (pinned to 8812064a01)

Solutions

  1. Retry the page once after a few seconds — registry contention is often transient
  2. Narrow the request: filter by status and type and lower limit before loading
  3. If persistent, capture a goroutine dump (/_status/stacks or debug zip) to find what holds the jobs registry mutex
  4. As a last resort raise the timeout passed to getJobs for this page on known-slow clusters

Example fix

// before
const [jobs, setJobs] = useState(null);
getJobs(req).then(setJobs);

// after: one bounded retry for the timeout-specific message
import { jobsTimeoutErrorMessage } from 'src/util/api';
const load = (attempt: number) =>
  getJobs(req).catch(err => {
    if (err.message === jobsTimeoutErrorMessage && attempt < 1) {
      return new Promise(r => setTimeout(r, 3000)).then(() => load(attempt + 1));
    }
    throw err;
  });
Defensive patterns

Strategy: retry

Validate before calling

// Keep requests bounded before loading
const bounded = {
  ...req,
  limit: Math.min(req.limit, 100),
  status: req.status || 'running',
  type: req.type || '',
};

Type guard

const isJobsTimeoutError = (e: unknown): e is Error =>
  e instanceof Error && e.message === 'Unable to retrieve the Jobs table.';

Try / catch

import { jobsTimeoutErrorMessage } from 'src/util/api';
const loadJobs = async (attempt = 0): Promise<JobsResponseMessage> => {
  try {
    return await getJobs(req);
  } catch (e) {
    if (e.message === jobsTimeoutErrorMessage && attempt < 2) {
      await new Promise(r => setTimeout(r, 3000 * (attempt + 1)));
      return loadJobs(attempt + 1);
    }
    throw e;
  }
};

Prevention

When it happens

Trigger: GET /_admin/jobs not answering within the timeout: the jobs registry mutex held by a long operation on a node, very high limit combined with thousands of jobs, slow RPC fan-out across many nodes, or an overloaded node.

Common situations: Large clusters with heavy backup/restore/changefeed job churn; opening the Jobs page unfiltered with a big limit during node stress; transient GC pauses or disk stalls on a node making job enumeration slow.

Related errors


AI-assisted analysis of cockroachdb/cockroach@8812064a01 (2026-08-15). Data as JSON: /api/errors/fbf3440cfb58fac6. Report an issue: GitHub.