The value was set. It was even spelled right. And every call still failed — because of one character you can't see.
The Telegram token was set on Vercel. I'd pasted it carefully. The dashboard showed it. And every single call came back 404 — like the token didn't exist.
"I set it. I checked the spelling three times. The dashboard literally showed the value. So how is the thing that's clearly there… not there? Nothing told me what was wrong."
"The value had a hidden trailing newline — a \n baked in when it was added the interactive way. bot<token>\n/sendMessage is a broken URL. I should've suspected the env value itself far sooner instead of re-checking the code that was already correct."
When you add an environment variable the easy way — typing it in, or echoing it into the command — an extra newline character can ride along on the end. You can't see it. The dashboard can't show it to you. But the code reads it, and now "true\n" is not "true", and https://app.com\n/chat is not a real address.
invisible, realA newline glued to the end of your value. Looks identical to the clean version everywhere a human looks.
"true\n" !== "true"Your if (flag === "true") silently goes false. The feature just quietly doesn't happen.
fails downstreamThe read site throws nothing. The breakage shows up far away from where it was actually born.
The model: imagine a label with an invisible extra space typed after the word. To you it reads "OPEN." To the machine that matches labels exactly, it's "OPEN " — a different word that matches nothing. The fix isn't smarter code; it's setting the value cleanly in the first place, and refusing to start if it isn't.
The token is on Vercel, it's correct, the dashboard shows it — and every call 404s with no error at the read site. What's the actual cause?
\n to the end. bot<token>\n/sendMessage is an invalid URL → 404. The value is present and "correct" everywhere you look, which is exactly why it's so hard to find. This same trap hit three different variables in one period."true\n" !== "true" → the flag read false → the app silently ran the wrong (pricier) model.https://app.com\n/chat is not a valid host → every coach reply came back 400.printf %s — no echo, no interactive prompt, no trailing newline.Same rule as always: answer it right, or the module isn't done.
\n defeats exact comparison and breaks URLs, with no error at the read site. Set values byte-exact, and guard against whitespace at startup. Module unlocked. ↓"Set" is not "clean." A value can be present, correct, and visible — and still carry an invisible character that breaks everything quietly. Guard the bytes, not just the spelling.
A real set-env.sh that adds Vercel vars the byte-exact way (no trailing newline, ever), plus a guard-env.js startup check that fails loud if any required var is missing or carries leading/trailing whitespace — the exact bug that bit three variables in one period.