KeygraphHQ/shannon · error · Error

Workspace not found: ${workspaceName} Expected path: ${sessi

Error message

Workspace not found: ${workspaceName}
Expected path: ${sessionPath}

What it means

Thrown by terminateExistingWorkflows (a plain Error, not PentestError) when the session.json for the requested workspace cannot be found at the resolved path. resolveSessionJsonPath prefers the .shannon/ internals dir and falls back to the legacy run-root; if neither yields a fileExists, the resume cannot proceed because there is no workflow id to terminate. This fires during the resume path before any Temporal call.

Source

Thrown at apps/worker/src/temporal/worker.ts:182

  };
}

function isValidWorkspaceName(name: string): boolean {
  return /^[a-zA-Z0-9][a-zA-Z0-9_-]{0,127}$/.test(name);
}

interface WorkspaceResolution {
  workflowId: string;
  sessionId: string;
  isResume: boolean;
  terminatedWorkflows: string[];
}

async function terminateExistingWorkflows(client: Client, workspaceName: string): Promise<string[]> {
  const sessionPath = resolveSessionJsonPath(path.join('./workspaces', workspaceName));

  if (!(await fileExists(sessionPath))) {
    throw new Error(`Workspace not found: ${workspaceName}\n` + `Expected path: ${sessionPath}`);
  }

  const session = await readJson<SessionJson>(sessionPath);

  const workflowIds = [
    session.session.originalWorkflowId || session.session.id,
    ...(session.session.resumeAttempts?.map((r) => r.workflowId) || []),
  ].filter((id): id is string => id != null);

  const terminated: string[] = [];

  for (const wfId of workflowIds) {
    try {
      const handle = client.workflow.getHandle(wfId);
      const description = await handle.describe();

      if (description.status.name === 'RUNNING') {
        console.log(`Terminating running scan: ${wfId}`);

View on GitHub (pinned to 1ae0a142f8)

Solutions

  1. Run ./shannon workspaces to list valid workspace names and confirm the spelling.
  2. Check that <repo>/workspaces/<workspaceName>/.shannon/session.json (or the legacy workspaces/<workspaceName>/session.json) actually exists.
  3. If the workspace was cleaned, start a new scan instead of resuming: ./shannon start -u <url> -r <repo> -w <new-name>.
  4. Ensure the resume command runs from the same directory (and SHANNON state root) as the original scan.
  5. For a pre-restructure workspace, run migrateLegacyWorkspaceLayout by starting the scan from the repo root so the migration upgrades it in place.

Example fix

// before: wrong workspace name on resume
//   ./shannon start -u <url> -r <repo> -w my-audt   (typo)
//   -> 'Workspace not found: my-audt ...'
// after: use the real name from `./shannon workspaces`
//   ./shannon workspaces   -> my-audit
//   ./shannon start -u <url> -r <repo> -w my-audit
Defensive patterns

Strategy: validation

Validate before calling

// Before calling resume, confirm the workspace's session.json exists at either layout
import { pathExists } from 'fs-extra';
const ws = path.join('./workspaces', workspaceName);
const modern = path.join(ws, '.shannon', 'session.json');
const legacy = path.join(ws, 'session.json');
if (!(await pathExists(modern)) && !(await pathExists(legacy))) {
  throw new Error(`Workspace '${workspaceName}' not found. Run \`./shannon workspaces\` to list valid names.`);
}

Type guard

function isValidWorkspaceName(name: string): boolean {
  return /^[a-zA-Z0-9][a-zA-Z0-9_-]{0,127}$/.test(name);
}

Try / catch

try {
  await resolveWorkspace(client, args);
} catch (e) {
  if (e instanceof Error && /Workspace not found/.test(e.message)) {
    // list real workspaces and either fix the name or start a new scan
    const names = await listWorkspaces();
    throw new Error(`Unknown workspace. Available: ${names.join(', ')}`);
  }
  throw e;
}

Prevention

When it happens

Trigger: resolveWorkspace calls terminateExistingWorkflows when resuming; it computes sessionPath = resolveSessionJsonPath('./workspaces/<workspaceName>') and checks fileExists. If the workspace name is wrong, the workspace was never created, the workspace dir was deleted (e.g. by ./shannon stop --clean), or it predates the .shannon/ restructure and the legacy fallback also misses, this throws.

Common situations: Typo in the -w <workspace> name. Resuming after ./shannon stop --clean wiped the workspace. The workspace lives under a different CWD than the one the resume is launched from. A pre-restructure workspace whose session.json the dual-read resolver cannot locate. Path case-sensitivity mismatch on a case-sensitive filesystem.

Related errors


AI-assisted analysis of KeygraphHQ/shannon@1ae0a142f8 (2026-08-12). Data as JSON: /api/errors/c5e5830cb4d42437. Report an issue: GitHub.