QuantumNous/new-api · error · Error
Failed to fetch channel key
Error message
Failed to fetch channel key
What it means
Thrown by fetchChannelKey in the channel drawer when getChannelKey(channelId, proofToken) resolves with success=false. The backend message (e.g. key locked, proof verification required) replaces this i18n fallback; on success the key is revealed and 'Channel key unlocked' is toasted.
Source
Thrown at web/src/features/channels/components/drawers/channel-mutate-drawer.tsx:1370
before: result.beforeCount,
after: result.afterCount,
}
)
)
}
}
const fetchChannelKey = useCallback(
async (proofToken?: string) => {
if (!channelId) {
throw new Error('Channel is not selected')
}
setIsChannelKeyLoading(true)
try {
const res = await getChannelKey(channelId, proofToken)
if (!res.success) {
throw new Error(res.message || t('Failed to fetch channel key'))
}
const keyValue = res.data?.key ?? ''
setChannelKey(keyValue)
toast.success(t('Channel key unlocked'))
return res
} finally {
setIsChannelKeyLoading(false)
}
},
[channelId, t]
)
const handleRevealKey = useCallback(async () => {
if (!channelId) return
try {
await withVerification(fetchChannelKey, {View on GitHub (pinned to e2c7aa7b10)
Solutions
- Read the toasted message — res.message carries the precise backend reason (proof required, forbidden, not found)
- If a proof token is required, complete the verification step first and pass the fresh proofToken to the call
- Confirm the logged-in account has permission to view channel keys (admin/root policy)
- Re-open the drawer from a valid channel row so channelId is current, and retry
Example fix
// before
const res = await getChannelKey(channelId, proofToken)
if (!res.success) {
throw new Error(res.message || t('Failed to fetch channel key'))
}
// after - branch on proof-required instead of a generic failure
const res = await getChannelKey(channelId, proofToken)
if (!res.success) {
if (res.message?.toLowerCase().includes('proof')) {
openProofVerification()
return
}
throw new Error(res.message || t('Failed to fetch channel key'))
} Defensive patterns
Strategy: try-catch
Validate before calling
if (!channelId) throw new Error('Channel is not selected') // keep guard
// ensure a fresh proof token when the backend requires verification Try / catch
setIsChannelKeyLoading(true)
try {
const res = await getChannelKey(channelId, proofToken)
if (!res.success) throw new Error(res.message || t('Failed to fetch channel key'))
setChannelKey(res.data?.key ?? '')
return res
} catch (error) {
toast.error(error instanceof Error ? error.message : t('Failed to fetch channel key'))
throw error // let proof-verification flows react
} finally {
setIsChannelKeyLoading(false)
} Prevention
- Check res.message for 'proof'/'verification' to route into the passkey flow instead of failing
- Never cache proof tokens — request a fresh one per unlock
- Verify the account has key-view permission before showing the unlock button
When it happens
Trigger: Requesting the channel key when the server requires a passkey/WebAuthn proof token that is missing/invalid, when the admin lacks permission to view keys, when the channel id does not exist, or when the session has expired.
Common situations: Key-view permission policy enabled and the account lacks it; proof token expired so a fresh verification flow is needed; channel deleted concurrently; 401 after idle session.
Related errors
- Failed to fetch usage
- Channel is not selected
- Failed to refresh credential
- Failed to fetch checkin status
- Failed to update settings
AI-assisted analysis of QuantumNous/new-api@e2c7aa7b10 (2026-08-15).
Data as JSON: /api/errors/82f38788e6064da3.
Report an issue: GitHub.