toeverything/AFFiNE · error · BadRequestException
Local workspaces don't support attachments or references.
Error message
Local workspaces don't support attachments or references.
What it means
Thrown when a message carries workspace-scoped context (attachments, blobs, scopeSelectors, preferredSourceIds, or focus selectors) but session.config.workspaceId does not resolve to a workspace via models.workspace.get — i.e. the session is bound to a local (client-side) workspace the server has no record of. Local workspaces have no server-side blob/doc storage, so references cannot be resolved. It surfaces as a BadRequestException (HTTP 400).
Source
Thrown at packages/backend/server/src/plugins/copilot/conversation/inbox.ts:68
options.blob ? [options.blob] : options.blobs || []
);
const focusSelectors = options.params?.focusSelectors;
const hasWorkspaceContext =
attachments.length > 0 ||
blobs.length > 0 ||
(Array.isArray(options.params?.scopeSelectors) &&
options.params.scopeSelectors.length > 0) ||
(Array.isArray(options.params?.preferredSourceIds) &&
options.params.preferredSourceIds.length > 0) ||
(focusSelectors === undefined
? session.config.focus.selectors.length > 0
: Array.isArray(focusSelectors) && focusSelectors.length > 0);
if (
hasWorkspaceContext &&
!(await this.models.workspace.get(session.config.workspaceId))
) {
throw new BadRequestException(
"Local workspaces don't support attachments or references."
);
}
if (blobs.length) {
await this.ac
.user(userId)
.workspace(session.config.workspaceId)
.allowLocal()
.assert('Workspace.Blobs.Write');
}
for (const blob of blobs) {
const uploaded = await this.storage.handleUpload(userId, blob);
const detectedMime =
sniffMime(uploaded.buffer, blob.mimetype)?.toLowerCase() ||
blob.mimetype;
let attachmentBuffer = uploaded.buffer;View on GitHub (pinned to b4c8548c09)
Solutions
- Strip attachments/blobs/scopeSelectors/preferredSourceIds/focusSelectors from the request when operating on a local workspace
- Enable cloud sync / sign in so the workspace exists server-side before attaching context
- Verify session.config.workspaceId is a cloud workspace id (models.workspace.get returns a record) before building the message
- In the UI, disable attachment and reference controls for local-workspace sessions
Example fix
// before
await inbox.createMessage(userId, {
sessionId,
blobs: [fileBlob], // local workspace -> 400
});
// after
const ws = await models.workspace.get(session.config.workspaceId);
if (!ws) {
await inbox.createMessage(userId, { sessionId, content }); // plain prompt, no context
} else {
await inbox.createMessage(userId, { sessionId, content, blobs: [fileBlob] });
} Defensive patterns
Strategy: validation
Validate before calling
const isCloudWorkspace = !!(await models.workspace.get(session.config.workspaceId));
const hasContext =
(options.attachments?.length ?? 0) > 0 ||
(options.blobs?.length ?? 0) > 0 ||
(options.params?.scopeSelectors?.length ?? 0) > 0 ||
(options.params?.preferredSourceIds?.length ?? 0) > 0;
if (!isCloudWorkspace && hasContext) {
delete options.attachments; delete options.blobs; delete options.params?.scopeSelectors; delete options.params?.preferredSourceIds;
} Try / catch
try {
return await inbox.createMessage(userId, options);
} catch (e) {
if (e instanceof BadRequestException && /Local workspaces/.test(e.message)) {
return inbox.createMessage(userId, { ...options, attachments: undefined, blobs: undefined });
}
throw e;
} Prevention
- Check workspace.isLocal before enabling attachment/reference UI affordances
- Default focus selectors to [] when none are explicitly chosen
- Test copilot flows in both local and cloud workspace modes
When it happens
Trigger: Sending createMessage with blobs, attachments, scopeSelectors, preferredSourceIds, or non-empty focus selectors while the session's workspaceId is a local workspace id; local docs synced without a server workspace record; a workspace deleted server-side while the session still references it.
Common situations: Client enables file attachments in a local-only AFFiNE workspace; doc reference chips added in local mode; workspace was deleted but an old copilot session pinned its id.
Related errors
AI-assisted analysis of toeverything/AFFiNE@b4c8548c09 (2026-08-18).
Data as JSON: /api/errors/1287a457ebaf1c3e.
Report an issue: GitHub.