QuantumNous/new-api · error · Error

Failed to start Telegram binding

Error message

Failed to start Telegram binding

What it means

Thrown by createBindFlow in the Telegram bind dialog when startTelegramBind() returns success=false or the payload lacks data.callback_url. The flow needs a backend-issued callback_url (plus flow_token) to render the Telegram widget; on failure the message is stored in the dialog's error state.

Solutions

  1. Verify Telegram OAuth settings (bot token, callback secret) are fully configured in admin system settings
  2. Read the dialog's error text — response.message identifies 'not configured' vs other causes
  3. Re-login and reopen the dialog to refresh the session-bound flow token
  4. Confirm the backend version returns { flow_token, callback_url } for the bind-start endpoint

Example fix

// before
if (!response.success || !response.data?.callback_url) {
  throw new Error(response.message || t('Failed to start Telegram binding'))
}
// after - distinguish 'not configured' with an actionable hint
if (!response.success || !response.data?.callback_url) {
  const msg = response.message || t('Failed to start Telegram binding')
  throw new Error(
    /config|provider/i.test(msg)
      ? `${msg} — ${t('Ask the admin to configure Telegram login')}`
      : msg
  )
}
Defensive patterns

Strategy: try-catch

Validate before calling

if (loading) return // prevent duplicate flow creation
// verify backend telegram OAuth is configured before showing the bind button

Type guard

const isBindFlowPayload = (d: unknown): d is { flow_token: string; callback_url: string } =>
  !!d && typeof (d as any).flow_token === 'string' && typeof (d as any).callback_url === 'string'

Try / catch

setLoading(true)
setError(null)
try {
  const response = await startTelegramBind()
  if (!response.success || !isBindFlowPayload(response.data)) {
    throw new Error(response.message || t('Failed to start Telegram binding'))
  }
  setFlowToken(response.data.flow_token)
  setCallbackUrl(new URL(response.data.callback_url, window.location.origin).toString())
} catch (bindError: unknown) {
  setError(bindError instanceof Error ? bindError.message : t('Failed to start Telegram binding'))
} finally {
  setLoading(false)
}

Prevention

When it happens

Trigger: Clicking start binding when the backend cannot initiate the flow: Telegram bot/OAuth settings missing server-side, the provider not configured, flow creation rejected, or response missing callback_url (contract violation).

Common situations: Admin enabled Telegram login in UI but did not set bot token/secret in system settings; backend env for the OAuth provider absent; session expired mid-dialog; backend version returns a different payload shape.

Related errors


AI-assisted analysis of QuantumNous/new-api@e2c7aa7b10 (2026-08-15). Data as JSON: /api/errors/2232408e68db99db. Report an issue: GitHub.

Appendix: source

Thrown at web/src/features/profile/components/dialogs/telegram-bind-dialog.tsx:63

  open,
  onOpenChange,
  botName,
  onSuccess,
}: TelegramBindDialogProps) {
  const { t } = useTranslation()
  const widgetRef = useRef<HTMLDivElement>(null)
  const [callbackUrl, setCallbackUrl] = useState<string | null>(null)
  const [flowToken, setFlowToken] = useState<string | null>(null)
  const [loading, setLoading] = useState(false)
  const [error, setError] = useState<string | null>(null)

  const createBindFlow = useCallback(async () => {
    setLoading(true)
    setError(null)
    try {
      const response = await startTelegramBind()
      if (!response.success || !response.data?.callback_url) {
        throw new Error(
          response.message || t('Failed to start Telegram binding')
        )
      }
      setFlowToken(response.data.flow_token)
      setCallbackUrl(
        new URL(response.data.callback_url, window.location.origin).toString()
      )
    } catch (bindError: unknown) {
      setError(
        bindError instanceof Error
          ? bindError.message
          : t('Failed to start Telegram binding')
      )
    } finally {
      setLoading(false)
    }
  }, [t])

View on GitHub (pinned to e2c7aa7b10)