yikart/AiToEarn · error · AppException
ChannelAuthCodeMissing
ChannelAuthCodeMissing
Error message
ResponseCode.ChannelAuthCodeMissing
What it means
Thrown in parseMiniAppCallback when the callback payload fails schema validation on the 'token' field, i.e. the authorization code/token from Douyin is absent or invalid. Distinct from CSRF failure: the session state is fine but there is no usable auth token to exchange.
Source
Thrown at project/aitoearn-backend/apps/aitoearn-server/src/core/channels/platforms/douyin/douyin-auth.provider.ts:241
state: input.query?.state ?? input.body?.state,
token: input.query?.token ?? input.body?.token,
nickname: input.query?.nickname ?? input.body?.nickname,
avatar: input.query?.avatar ?? input.body?.avatar,
tickets: input.body?.tickets,
}
if (payload.token === undefined && payload.tickets === undefined) {
return undefined
}
const result = DouyinMiniAppCallbackSchema.safeParse(payload)
if (!result.success) {
const hasInvalidState = result.error.issues.some(issue => issue.path[0] === 'state')
const hasInvalidToken = result.error.issues.some(issue => issue.path[0] === 'token')
if (hasInvalidState) {
throw new AppException(ResponseCode.ChannelAuthCsrfInvalid)
}
if (hasInvalidToken) {
throw new AppException(ResponseCode.ChannelAuthCodeMissing)
}
throw new AppException(ResponseCode.ChannelAuthorizationFailed)
}
assertParsedCallbackState(result.data.state, input.session.id)
return result.data
}
private hasMiniAppScope(scopes: string | undefined, scope: string) {
return !!scopes?.split(/[,\s]+/).includes(scope)
}
private maskOpenId(openId: string) {
if (openId.length <= 8) {
return openId
}
View on GitHub (pinned to d3aa8bea5b)
Solutions
- Have the user restart the mini-app authorization so Douyin issues a fresh token
- Inspect the raw callback payload to confirm the token parameter name/value matches the schema
- Check the frontend callback handler isn't stripping or renaming the token param before calling the backend
Defensive patterns
Strategy: validation
Validate before calling
const token = callbackPayload?.token
if (typeof token !== 'string' || token.length === 0) {
throw new Error('Authorization callback is missing the token/code parameter')
} Type guard
function hasAuthCode(payload: unknown): payload is { token: string } {
return typeof payload === 'object' && payload !== null && typeof (payload as any).token === 'string' && (payload as any).token.length > 0
} Try / catch
try {
await provider.miniAppCallback(payload)
} catch (e) {
if (e instanceof AppException && e.code === 'ChannelAuthCodeMissing') {
return { restartAuth: true, message: 'No authorization token received; please authorize again' }
}
throw e
} Prevention
- Check for Douyin error codes in the callback before forwarding (user-cancelled auth yields no token)
- Never reuse or cache callback URLs that contain a consumed token
- Keep frontend param forwarding aligned with the backend schema field names
When it happens
Trigger: Douyin mini-app callback where 'token' (the auth code field) is missing, empty, or of the wrong type per DouyinMiniAppCallbackSchema.
Common situations: User landed on the callback page without completing authorization, Douyin returned an error code instead of a token, frontend dropped the token query parameter, or the callback URL was visited directly.
Related errors
- ChannelAuthCsrfInvalid
- No subtitle entries in response
- No response from Gemini
- Invalid subtitle data: ${z.prettifyError(result.error)}
- Canvas not provided and no vid:// video source found in Trac
AI-assisted analysis of yikart/AiToEarn@d3aa8bea5b (2026-08-31).
Data as JSON: /api/errors/e410e7ca755626d0.
Report an issue: GitHub.