toeverything/AFFiNE · error · SpaceNotFound

space_not_found

space_not_found

Error message

Space ${spaceId} not found.

What it means

Thrown by the workspace(id) GraphQL query when the caller passes the Workspace.Read access assertion but models.workspace.get(id) returns null — no workspace with that id exists (deleted or never existed).

Solutions

  1. Re-fetch the user's workspace list and use a current workspace id.
  2. Confirm the id is the exact workspace identifier (no encoding issues, no doc id passed instead of workspace id).
  3. If the workspace was deleted unexpectedly, check the deletion audit/records.
Defensive patterns

Strategy: try-catch

Validate before calling

// Before deep-linking, confirm the id is in the user's workspace list
const list = await gql.request(GET_WORKSPACES);
if (!list.workspaces.some(w => w.id === targetId)) {
  router.replace('/404');
}

Type guard

const isSpaceNotFound = (e: unknown): boolean =>
  getGraphqlErrorCode(e) === 'space_not_found';

Try / catch

try {
  const { workspace } = await gql.request(GET_WORKSPACE, { id });
} catch (e) {
  if (isSpaceNotFound(e)) router.replace('/404');
}

Prevention

When it happens

Trigger: Querying workspace(id: "...") with a deleted, malformed, or random id that the user happens to be allowed to assert on.

Common situations: Client holds a stale workspace id after deletion (page/doc bookmark), ids copied with whitespace or truncation, or scripts iterating ids that were cleaned up.

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 toeverything/AFFiNE@2af30773ae (2026-08-18). Data as JSON: /api/errors/a6bc5f668e274ac8. Report an issue: GitHub.

Appendix: source

Thrown at packages/backend/server/src/core/workspaces/resolvers/workspace.ts:176

    );

    return workspaces.map(workspace => ({
      ...workspace,
      permission: map.get(workspace.id),
      role: map.get(workspace.id),
    }));
  }

  @Query(() => WorkspaceType, {
    description: 'Get workspace by id',
  })
  async workspace(@CurrentUser() user: CurrentUser, @Args('id') id: string) {
    await this.ac.user(user.id).workspace(id).assert('Workspace.Read');

    const workspace = await this.models.workspace.get(id);

    if (!workspace) {
      throw new SpaceNotFound({ spaceId: id });
    }

    return workspace;
  }

  @Query(() => WorkspaceRolePermissions, {
    description: 'Get workspace role permissions',
    deprecationReason: 'use WorkspaceType[permissions] instead',
  })
  async workspaceRolePermissions(
    @CurrentUser() user: CurrentUser,
    @Args('id') id: string
  ): Promise<WorkspaceRolePermissions> {
    const { role, permissions } = await this.ac
      .user(user.id)
      .workspace(id)
      .permissions();

View on GitHub (pinned to 2af30773ae)