affaan-m/ECC · error · Error

invalid interaction id/token

Error message

invalid interaction id/token

What it means

interactionCallbackUrl builds the Discord interactions callback endpoint from an interaction's id and token. The id must be a valid snowflake and the token must match /^[A-Za-z0-9._-]{1,255}$/; otherwise it throws 'invalid interaction id/token' rather than issuing a request to a malformed endpoint. This protects against hostile or corrupted payloads delivered by the Discord gateway/HTTP flow.

Solutions

  1. Log (safely, without printing the token) the interaction id and token presence before building the URL to see which field fails validation.
  2. Use interaction.id and interaction.token exactly as delivered by Discord's payload; do not re-encode or trim them.
  3. Fix the serialization path so id/token survive transit (store as strings, not numbers, to avoid precision loss on snowflakes).
  4. Drop and re-acknowledge corrupt interactions instead of retrying the callback.

Example fix

// before
const url = interactionCallbackUrl({ id: payload.d.interaction_id, token: payload.d.interaction_token });
// after (use the nested interaction object as delivered)
const interaction = payload.d.interaction ?? payload.d;
const url = interactionCallbackUrl(interaction);
Defensive patterns

Strategy: type-guard

Validate before calling

const SNOWFLAKE_RE = /^\d{17,20}$/;
const TOKEN_RE = /^[A-Za-z0-9._-]{1,255}$/;
function canBuildCallbackUrl(interaction) {
  return SNOWFLAKE_RE.test(String(interaction?.id ?? '')) && TOKEN_RE.test(String(interaction?.token ?? ''));
}
if (!canBuildCallbackUrl(interaction)) return; // skip/drop corrupt interaction

Type guard

const hasValidInteraction = (i) =>
  typeof i === 'object' && i !== null &&
  /^\d+$/.test(String(i.id ?? '')) &&
  typeof i.token === 'string' && /^[A-Za-z0-9._-]{1,255}$/.test(i.token);

Try / catch

try {
  await fetch(interactionCallbackUrl(interaction), init);
} catch (err) {
  if (err.message === 'invalid interaction id/token') {
    console.warn(`Dropping interaction ${interaction?.id ?? '(unknown id)'}: malformed id/token`);
    return;
  }
  throw err;
}

Prevention

When it happens

Trigger: Handling an interaction object that is missing id or token (undefined), contains characters outside the allowed set (URL-encoded or padded values), or was reconstructed from a log/queue where fields were truncated or serialized incorrectly.

Common situations: Replaying interactions from a dead-letter queue with lossy serialization; forwarding interactions between services and dropping optional fields; processing a malformed/legacy interaction payload; test harnesses feeding hand-built interaction fixtures.

Understand the failure class

Background: "invalid id" errors: invalid identifier format — why libraries reject IDs before lookup, and how to fix them — this error's family across 37 libraries.

Related errors


AI-assisted analysis of affaan-m/ECC@8321021c54 (2026-09-16). Data as JSON: /api/errors/3afd2d6199c09503. Report an issue: GitHub.

Appendix: source

Thrown at scripts/discord/ecc-bot.mjs:45

const API = 'https://discord.com/api/v10';

// Strip CR/LF from string args so Discord-payload-controlled values (command
// names, usernames) cannot forge or inject extra log lines (log injection).
const log = (...a) =>
  console.log(new Date().toISOString(), ...a.map(x => (typeof x === 'string' ? x.replace(/[\r\n]+/g, ' ') : x)));

// Interaction ids are Discord snowflakes (numeric) and tokens are a bounded
// URL-safe set. Validate before building the callback URL so a malformed or
// hostile gateway payload cannot inject path segments / alter the request
// target (SSRF). The host is always the fixed API constant.
const SNOWFLAKE_RE = /^[0-9]{1,20}$/;
const INTERACTION_TOKEN_RE = /^[A-Za-z0-9._-]{1,255}$/;

function interactionCallbackUrl(interaction) {
  const id = String(interaction?.id ?? '');
  const token = String(interaction?.token ?? '');
  if (!SNOWFLAKE_RE.test(id) || !INTERACTION_TOKEN_RE.test(token)) {
    throw new Error('invalid interaction id/token');
  }
  return `${API}/interactions/${id}/${token}/callback`;
}

// Clamp a remote-supplied timer interval to a sane range so a hostile/bogus
// heartbeat_interval cannot spin a tight loop or hang the bot (resource
// exhaustion). Discord's real value is ~41250ms.
function clampHeartbeatInterval(value) {
  const n = Number(value);
  if (!Number.isFinite(n)) return 41250;
  return Math.max(1000, Math.min(n, 600000));
}

// ---------- skill + docs lookup (local clone as the data source) ----------

function parseFrontmatter(text) {
  const m = text.match(/^---\n([\s\S]*?)\n---/);
  if (!m) return {};

View on GitHub (pinned to 8321021c54)