mattermost-community/focalboard · warning · Error
ErrorId.InvalidReadOnlyBoard
ErrorId.InvalidReadOnlyBoard
Error message
InvalidReadOnlyBoard
What it means
loadBoardOptions throws new Error(ErrorId.InvalidReadOnlyBoard) when a board fetch returns nothing while in read-only (shared board) mode. In read-only mode a missing board means the read-only token was invalid or the board no longer exists.
Source
Thrown at webapp/src/store/initialLoad.ts:57
boardsMemberships,
boardTemplates,
limits,
myConfig,
}
},
)
export const initialReadOnlyLoad = createAsyncThunk(
'initialReadOnlyLoad',
async (boardId: string) => {
const [board, blocks] = await Promise.all([
client.getBoard(boardId),
client.getAllBlocks(boardId),
])
// if no board, read_token invalid
if (!board) {
throw new Error(ErrorId.InvalidReadOnlyBoard)
}
return {board, blocks}
},
)
export const loadBoardData = createAsyncThunk(
'loadBoardData',
async (boardID: string) => {
const blocks = await client.getAllBlocks(boardID)
return {
blocks,
}
},
)
export const loadBoards = createAsyncThunk(
'loadBoards',View on GitHub (pinned to a84bbb65e3)
Solutions
- Regenerate the share/read-only link and send a fresh one to the user
- Verify the board still exists and sharing (read-only access) is still enabled for it
- Catch the error and show an 'invalid or expired link' page instead of a blank screen
- Check that the read-only token is being sent with the getBoard/getAllBlocks requests
Example fix
// before
const {board, blocks} = await loadBoardOptions(boardId) // throws
// after
try {
const {board, blocks} = await loadBoardOptions(boardId)
} catch (e) {
if (e.message === 'InvalidReadOnlyBoard') {
renderExpiredSharePage()
}
} Defensive patterns
Strategy: try-catch
Validate before calling
const board = await client.getBoard(boardId).catch(() => null)
if (!board) {
showInvalidShareLinkPage()
} Type guard
function isInvalidReadOnlyBoardError(e: unknown): e is Error {
return e instanceof Error && e.message === 'InvalidReadOnlyBoard'
} Try / catch
try {
const {board, blocks} = await loadBoardOptions(boardId)
} catch (e) {
if (isInvalidReadOnlyBoardError(e)) {
render('This shared link is invalid or has expired')
return
}
throw e
} Prevention
- Set sensible expiry/rotation for share tokens and communicate it to users
- Check board existence before sharing links
- Render a friendly expired-link page instead of a crash
- Log token failures to detect revoked or mistyped links
When it happens
Trigger: Opening a shared/read-only board link where client.getBoard(boardId) returns null because the read token is invalid/expired or the board was deleted.
Common situations: Shared board links past their expiry, revoked sharing tokens, deleted boards still bookmarked, or mistyped board IDs in shared links.
Related errors
AI-assisted analysis of mattermost-community/focalboard@a84bbb65e3 (2026-08-30).
Data as JSON: /api/errors/ba71388763859c8a.
Report an issue: GitHub.