OtterMind/Chat2DB · error · BusinessException
largeCellValue.tokenForbidden
largeCellValue.tokenForbidden
Error message
largeCellValue.tokenForbidden
What it means
Thrown by DbLargeValueTokenServiceImpl.validateOwner when the token's userId or organizationId does not match the current Context (context.getLoginUser().getId() / context.getOrganizationId()). Tokens are scoped to the user+org that triggered the result render, so a mismatch is treated as unauthorized access. Resolves to 'You do not have permission to access this large value'. This is an authorization boundary.
Source
Thrown at chat2db-community-server/chat2db-community-domain/chat2db-community-domain-core/src/main/java/ai/chat2db/community/domain/core/impl/db/DbLargeValueTokenServiceImpl.java:154
.primaryKey(primaryKey)
.userId(userId)
.organizationId(organizationId)
.expiresAt(Instant.now().plus(DEFAULT_TTL))
.valueType(cell.getValueType())
.sqlType(cell.getSqlType())
.columnType(cell.getColumnType())
.sizeBytes(cell.getSizeBytes())
.sizeChars(cell.getSizeChars())
.build();
}
private void validateOwner(LargeValueToken token) {
Context context = ContextUtils.queryContext();
Long organizationId = context == null ? null : context.getOrganizationId();
LoginUser loginUser = context == null ? null : context.getLoginUser();
Long userId = loginUser == null ? null : loginUser.getId();
if (!Objects.equals(token.getUserId(), userId) || !Objects.equals(token.getOrganizationId(), organizationId)) {
throw new BusinessException("largeCellValue.tokenForbidden");
}
}
private Object getLocatorValue(ResultCell cell) {
return cell.getRawValue() == null ? cell.getValue() : cell.getRawValue();
}
}
View on GitHub (pinned to 5ee1e990e7)
Solutions
- Only request large values for cells rendered in the current user's own session.
- Ensure ContextUtils.queryContext() carries a valid LoginUser before calling requireValid.
- Do not share largeValueId values between users; they are per-user opaque references.
Defensive patterns
Strategy: validation
Validate before calling
Context ctx = ContextUtils.queryContext();
LoginUser u = ctx == null ? null : ctx.getLoginUser();
if (u == null || u.getId() == null) {
// require login before large-value access
} Type guard
boolean tokenOwnedByCaller(LargeValueToken t) {
Context c = ContextUtils.queryContext();
LoginUser u = c == null ? null : c.getLoginUser();
Long uid = u == null ? null : u.getId();
Long oid = c == null ? null : c.getOrganizationId();
return Objects.equals(t.getUserId(), uid) && Objects.equals(t.getOrganizationId(), oid);
} Prevention
- Never share largeValueId across users/sessions.
- Ensure an authenticated context is bound before calling requireValid.
When it happens
Trigger: One user attempting to read a large-cell token issued to another user; an organization mismatch (multi-tenant); a token id leaked/replayed in a different session; context not set so both ids resolve to null but the token was issued under a real user.
Common situations: Shared/copy-pasted URLs containing a largeValueId across users; a session that lost its login context (both ids null) trying to read a user-bound token; cross-tenant token reuse.
Understand the failure class
- Authentication and authorization failures — expired tokens, bad credentials, and missing scopes.
Related errors
- largeCellValue.tokenRequired
- largeCellValue.tokenExpired
- largeCellValue.rowNotFound
- largeCellValue.readFailed
- largeCellValue.downloadFailed
AI-assisted analysis of OtterMind/Chat2DB@5ee1e990e7 (2026-08-14).
Data as JSON: /api/errors/06ac96208cf4c638.
Report an issue: GitHub.