Mintplex-Labs/anything-llm · warning

Workspace or thread is not valid.

Error message

Workspace ${slug} or thread ${threadSlug} is not valid.

What it means

HTTP 400 from POST /api/v1/workspace/:slug/thread/:threadSlug/stream-chat when either the workspace or thread lookup is null, with one message covering both cases. Subtlety: the code calls WorkspaceThread.get({workspace_id: workspace.id}) BEFORE the null check on workspace, so a completely missing workspace usually throws a TypeError ('Cannot read properties of null') that lands in the catch handler instead; this 400 therefore fires most often when the workspace resolves but the thread does not, or when Workspace.get returns undefined.

Solutions

  1. Check the thread exists under this workspace via the thread chats endpoint first
  2. If the error string appears with a valid workspace, focus on the threadSlug - it is the usual culprit
  3. If the server log shows a TypeError instead, your workspace slug itself is wrong - resolve it via GET /api/v1/workspaces
  4. Create the thread with POST /v1/workspace/:slug/thread/new when missing and use the returned slug

Example fix

// before
await streamThreadChat(slug, threadSlug, message);
// after
const ok = await fetch(`${BASE}/api/v1/workspace/${slug}/thread/${threadSlug}/chats`, { headers: AUTH }).then(r => r.ok);
if (!ok) threadSlug = (await createThread(slug)).slug; // then stream
Defensive patterns

Strategy: validation

Validate before calling

const ok = await fetch(`${BASE}/api/v1/workspace/${slug}/thread/${threadSlug}/chats`, { headers: AUTH }).then(r => r.ok);
if (!ok) threadSlug = (await createThread(slug)).slug;

Type guard

function isWorkspaceOrThreadInvalid(d) { return d?.type === 'abort' && /is not valid/.test(d.error ?? ''); }

Try / catch

try { await streamThreadChat(slug, threadSlug, body); }
catch (e) { if (isWorkspaceOrThreadInvalid(e.payload)) { await revalidateSlugs(); } else throw e; }

Prevention

When it happens

Trigger: Valid workspace slug with a thread slug that is deleted or belongs to another workspace (400); completely unknown workspace slug often surfaces as the catch path with a TypeError message rather than this 400; sending thread name instead of thread slug.

Common situations: Stale thread references after thread deletion; duplicated workspaces reusing thread slugs; clients assuming thread slugs are global.

Understand the failure class

Background: 'Could not be found', 'does not exist', 'not found in database': the resource-not-found family when an ID, slug, key, or URI lookup comes back empty — this error's family across 20 libraries.

Related errors


AI-assisted analysis of Mintplex-Labs/anything-llm@3aec848f28 (2026-08-18). Data as JSON: /api/errors/11aa4ab2be8e85ed. Report an issue: GitHub.

Appendix: source

Thrown at server/endpoints/api/workspaceThread/index.js:591

      }
      */
      try {
        const { slug, threadSlug } = request.params;
        const {
          message,
          mode = null,
          userId,
          attachments = [],
          reset = false,
        } = reqBody(request);
        const workspace = await Workspace.get({ slug: String(slug) });
        const thread = await WorkspaceThread.get({
          slug: String(threadSlug),
          workspace_id: workspace.id,
        });

        if (!workspace || !thread) {
          response.status(400).json({
            id: uuidv4(),
            type: "abort",
            textResponse: null,
            sources: [],
            close: true,
            error: `Workspace ${slug} or thread ${threadSlug} is not valid.`,
          });
          return;
        }

        const resolvedMode = mode ?? workspace.chatMode;
        if (
          (!message?.length || !VALID_CHAT_MODE.includes(resolvedMode)) &&
          !reset
        ) {
          response.status(400).json({
            id: uuidv4(),
            type: "abort",

View on GitHub (pinned to 3aec848f28)