Logic:Get User (DB) $\rightarrow$ Fetch Questions $\rightarrow$ Calculate Score (Code) $\rightarrow$ Save State (DB) $\rightarrow$ Send Next Question.
Design Rationale:
We switched from “Wait” nodes to a Stateless (Database-driven) approach because Telegram button clicks trigger new executions, causing the Wait node context to be lost.
The Failure:
The bot gets stuck in a loop (repeating Question 2) because the Postgres - Get User node returns an empty item [{}] even though the user definitely exists in the database.
Because it returns empty, the Logic node assumes a “New User,” resets the sequence to 1, and the user never progresses.
What We Have Tried (Troubleshooting):
Verified Data Exists: Checked Supabase directly; User 648416370 exists with current_sequence: 2.
Checked RLS: Row Level Security is OFF in Supabase.
Data Types: The DB column is int8 (BigInt). We tried casting the query to text to avoid type mismatches: WHERE telegram_id::text = $1::text.
Node Settings: Set “Always Output Data” to true (returns an empty item instead of null).
Trigger: Verified the Trigger is correctly receiving the callback_query and ID.
Current Status:
The node executes successfully but returns 0 results for a known ID. Suspecting a connection/environment mismatch or a specific n8n<->Supabase parameter parsing issue.
after an hour with gemini Topic: Solved - Postgres Node returns empty data for existing Telegram ID (BigInt/Text Mismatch)
The Issue: I was building a Telegram bot where n8n needed to check if a user existed (SELECT * FROM users WHERE id = $1). Even though the user existed in Supabase (verified via SQL), the n8n Postgres node kept returning 0 items (Empty).
Root Cause: A persistent mismatch between Telegram IDs (which are huge numbers) and Postgres Int8 columns. N8n/JavaScript handles these large numbers inconsistently (sometimes as Numbers, sometimes Strings), causing the WHERE clause to fail silently (e.g., 123 !== "123").
The Solution: The “Atomic Upsert” Pattern Instead of trying to debug the SELECT node’s type matching, we replaced the “Get User” node with an “Initialize User” node using a single SQL INSERT command with RETURNING *.
The Magic Query:
SQL
INSERT INTO "HP_Users" (telegram_id)
VALUES ('{{ ($json.callback_query ? $json.callback_query.from.id : $json.message.chat.id).toString() }}')
ON CONFLICT (telegram_id)
DO UPDATE SET last_question_ts = NOW()
RETURNING *;
Why this works:
Bypasses the Search: We don’t rely on a WHERE clause matching the ID perfectly.
Handles Both Cases:
New User: It inserts them.
Existing User: It hits a conflict and harmlessly updates a timestamp.
Guaranteed Return: The RETURNING * command forces the database to send back the user’s current state (Score/Sequence) in the same step.
No Logic Branching: We deleted the “If User Exists” logic node entirely because this one SQL node handles both creation and retrieval.