MemPalace/mempalace · error · DaemonError

unknown job id: {job_id}

Error message

unknown job id: {job_id}

What it means

DaemonError from QueueStore.get() (mempalace/daemon.py:605): a SELECT on the jobs table for the given id returned no row. Job ids are minted at submit time and persisted in queue.sqlite3, so this means the id was never issued by this daemon's queue, or the queue database was reset/rotated since.

Source

Thrown at mempalace/daemon.py:605

                    error_json = ?
                WHERE id = ? AND state = 'running'
                  AND (? IS NULL OR started_at = ?)
                """,
                (
                    json.dumps(error or {}, ensure_ascii=False) if error else None,
                    job_id,
                    claimed_started_at,
                    claimed_started_at,
                ),
            )
            row = conn.execute("SELECT * FROM jobs WHERE id = ?", (job_id,)).fetchone()
            return self._row_to_job(row)

    def get(self, job_id: str) -> Job:
        with self._lock, self._connect() as conn:
            row = conn.execute("SELECT * FROM jobs WHERE id = ?", (job_id,)).fetchone()
            if row is None:
                raise DaemonError(f"unknown job id: {job_id}")
            return self._row_to_job(row)

    def list(self, limit: int = 20) -> list[Job]:
        with self._lock, self._connect() as conn:
            rows = conn.execute(
                "SELECT * FROM jobs ORDER BY created_at DESC LIMIT ?",
                (max(1, int(limit)),),
            ).fetchall()
            return [self._row_to_job(row) for row in rows]

    def counts(self) -> dict[str, int]:
        with self._lock, self._connect() as conn:
            rows = conn.execute("SELECT state, COUNT(*) AS n FROM jobs GROUP BY state").fetchall()
            return {str(row["state"]): int(row["n"]) for row in rows}

    @staticmethod
    def _row_to_job(row: sqlite3.Row) -> Job:
        def _loads(value):

View on GitHub (pinned to 06cb6987f0)

Solutions

  1. Re-check the job id against the value returned from submit(); print it verbatim rather than hand-copying.
  2. Use client.list_jobs() (QueueStore.list) to confirm the id exists in the current queue.
  3. If the queue was reset, treat the missing job as lost and resubmit the work.
  4. Confirm you are talking to the same palace_path/state dir that accepted the submission.

Example fix

# before
job = client.get_job("job-123")  # typo / stale id

# after
result = client.submit("index", payload)
job = client.wait_for_job(result["job_id"], timeout=30)  # use the returned id
Defensive patterns

Strategy: validation

Validate before calling

ids = {job["id"] for job in client.list_jobs(limit=100)}
if job_id not in ids:
    # resubmit or skip — do not call get_job

Type guard

import re

def is_job_id(value: object) -> bool:
    return isinstance(value, str) and bool(re.fullmatch(r"[A-Za-z0-9_-]+", value))

Try / catch

from mempalace.daemon import DaemonError

try:
    job = client.get_job(job_id)
except DaemonError:
    # id never issued by this queue (reset/typo/other palace) — resubmit work
    result = client.submit(kind, payload)

Prevention

When it happens

Trigger: Calling client.get_job(job_id) with a typo'd or truncated id; polling a job id from a previous daemon incarnation after the queue.sqlite3 was recreated; a job id from a different palace_path whose state dir hosts a separate queue; pruned/compacted job rows.

Common situations: Persisting job ids across daemon restarts in a hook or script and resuming after the state dir was rebuilt; copy-pasting ids from logs of a different environment; long-running orchestrators holding stale handles.

Related errors


AI-assisted analysis of MemPalace/mempalace@06cb6987f0 (2026-08-15). Data as JSON: /api/errors/194769807289e7b9. Report an issue: GitHub.