koala73/worldmonitor · critical · Error
[createProLaunchBroadcast] PRO_LAUNCH_PHYSICAL_ADDRESS is st
Error message
[createProLaunchBroadcast] PRO_LAUNCH_PHYSICAL_ADDRESS is still a placeholder ("${PRO_LAUNCH_PHYSICAL_ADDRESS}"). Set the real CAN-SPAM postal address in convex/broadcast/proLaunchEmailContent.ts before sending. What it means
Hard-gate thrown by createProLaunchBroadcast when PRO_LAUNCH_PHYSICAL_ADDRESS (imported from proLaunchEmailContent.ts) still contains the substring 'TBD' or 'placeholder'. The guard exists because CAN-SPAM requires a valid postal address in every commercial email footer; shipping the literal placeholder string would be non-compliant. It is a deliberate pre-flight check that fires before any Resend API call is made.
Source
Thrown at convex/broadcast/sendBroadcast.ts:81
nameSuffix: v.optional(v.string()),
},
handler: async (_ctx, { segmentId, nameSuffix }) => {
const apiKey = process.env.RESEND_API_KEY;
if (!apiKey) {
throw new Error("[createProLaunchBroadcast] RESEND_API_KEY not set");
}
// Hard-gate: refuse to ship the placeholder physical address.
// CAN-SPAM requires a valid postal address in every commercial
// email footer; sending the literal "physical address TBD" string
// is non-compliant and embarrassing. Edit
// `PRO_LAUNCH_PHYSICAL_ADDRESS` in proLaunchEmailContent.ts to the
// real postal address before invoking this action.
if (
PRO_LAUNCH_PHYSICAL_ADDRESS.includes("TBD") ||
PRO_LAUNCH_PHYSICAL_ADDRESS.includes("placeholder")
) {
throw new Error(
`[createProLaunchBroadcast] PRO_LAUNCH_PHYSICAL_ADDRESS is still a placeholder ("${PRO_LAUNCH_PHYSICAL_ADDRESS}"). ` +
"Set the real CAN-SPAM postal address in convex/broadcast/proLaunchEmailContent.ts before sending.",
);
}
const name =
nameSuffix && nameSuffix.length > 0
? `PRO Launch — ${nameSuffix}`
: `PRO Launch — ${new Date().toISOString().slice(0, 10)}`;
const res = await fetch(`${RESEND_API_BASE}/broadcasts`, {
method: "POST",
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${apiKey}`,
"User-Agent": USER_AGENT,
},
body: JSON.stringify({View on GitHub (pinned to ffec79ac33)
Solutions
- Edit PRO_LAUNCH_PHYSICAL_ADDRESS in convex/broadcast/proLaunchEmailContent.ts to the real company postal address (currently 'WorldMonitor FZ LLC, Dubai - United Arab Emirates' — confirm it is still correct).
- Ensure the new value contains neither 'TBD' nor 'placeholder' as a substring (the check is case-sensitive on those exact lowercase strings).
- Re-run createProLaunchBroadcast after redeploying the Convex function so the updated constant is loaded.
Example fix
// before export const PRO_LAUNCH_PHYSICAL_ADDRESS = "physical address TBD"; // after export const PRO_LAUNCH_PHYSICAL_ADDRESS = "WorldMonitor FZ LLC, Dubai - United Arab Emirates";
Defensive patterns
Strategy: validation
Validate before calling
import { PRO_LAUNCH_PHYSICAL_ADDRESS } from "./proLaunchEmailContent";
function assertPhysicalAddressReady(): void {
if (PRO_LAUNCH_PHYSICAL_ADDRESS.includes("TBD") || PRO_LAUNCH_PHYSICAL_ADDRESS.includes("placeholder")) {
throw new Error("PRO_LAUNCH_PHYSICAL_ADDRESS is a placeholder — set the real CAN-SPAM address first.");
}
}
// call before createProLaunchBroadcast Prevention
- Treat proLaunchEmailContent.ts as a locked content file — change it only in a dedicated PR, not inline with operational work.
- Add a CI lint that greps PRO_LAUNCH_PHYSICAL_ADDRESS for 'TBD'/'placeholder' and fails the build.
- Run createProLaunchBroadcast in a dry-run/staging Convex deployment before production.
When it happens
Trigger: Invoking createProLaunchBroadcast via `npx convex run broadcast/sendBroadcast:createProLaunchBroadcast '{"segmentId":"seg_xxx"}'` while PRO_LAUNCH_PHYSICAL_ADDRESS in convex/broadcast/proLaunchEmailContent.ts is set to a value containing 'TBD' or 'placeholder' (e.g. 'physical address TBD'). Also fires if a future edit reintroduces either substring.
Common situations: A developer clones the repo and the address constant is still the placeholder default. An operator reverts proLaunchEmailContent.ts during a merge conflict resolution and the placeholder comes back. The address was intentionally set to a temporary string during content drafting and never replaced before the send window.
Related errors
- [backfillCanary250] RESEND_API_KEY not set — run with the sa
- [backfillCanary250] CANARY_SENT_AT_MS failed Date.parse — ch
- [initRamp] rampCurve must be non-empty
- [initRamp] seedLastWaveBroadcastId and seedLastWaveSentAt mu
- [initRamp] waveLabelOffset=${offset} signals resumption afte
AI-assisted analysis of koala73/worldmonitor@ffec79ac33 (2026-08-12).
Data as JSON: /api/errors/a990e0c1fb8f2868.
Report an issue: GitHub.