{"record":{"id":"51bdcb31cc7b9a9a","repo":"decolua/9router","slug":"missing-zed-callback-url","errorCode":null,"errorMessage":"Missing Zed callback URL","messagePattern":"Missing Zed callback URL","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"open-sse/shared/zedAuth.js","lineNumber":104,"sourceCode":"    `${normalizeBaseUrl(config.webBaseUrl, ZED_WEB_BASE_URL)}/native_app_signin`,\n  );\n  signInUrl.searchParams.set(\"native_app_port\", String(nativeAppPort));\n  signInUrl.searchParams.set(\"native_app_public_key\", publicKeyString);\n  if (systemId) signInUrl.searchParams.set(\"system_id\", systemId);\n\n  return {\n    authUrl: signInUrl.toString(),\n    privateKeyVerifier: encodeZedPrivateKeyVerifier(privateKey),\n    nativeAppPort,\n    systemId,\n    publicKey: publicKeyString,\n  };\n}\n\n/** Parse the pasted native-app callback URL/JSON/query into userId + encrypted token. */\nexport function parseZedCallbackPayload(input) {\n  const raw = String(input || \"\").trim();\n  if (!raw) throw new Error(\"Missing Zed callback URL\");\n\n  let data = {};\n  try {\n    data = JSON.parse(raw);\n  } catch {\n    let url;\n    try {\n      url = new URL(raw);\n    } catch {\n      try {\n        url = new URL(`http://127.0.0.1/?${raw.replace(/^\\?/, \"\")}`);\n      } catch {\n        throw new Error(\"Invalid Zed callback URL\");\n      }\n    }\n    url.searchParams.forEach((value, key) => {\n      data[key] = value;\n    });","sourceCodeStart":86,"sourceCodeEnd":122,"githubUrl":"https://github.com/decolua/9router/blob/90b52e06ffd666b7929554211474d01588f6b1f8/open-sse/shared/zedAuth.js#L86-L122","documentation":"parseZedCallbackPayload converts the pasted native-app callback URL/JSON/query into { userId, encryptedAccessToken }. It throws when the input string is empty after trimming — there is no callback data to parse at all. It is the first guard before JSON/URL parsing, so it means the caller supplied nothing rather than malformed data.","triggerScenarios":"Calling parseZedCallbackPayload with undefined, null, '', or whitespace-only input — e.g. the user clicked 'finish login' without pasting the callback URL, or the UI passed an unset state variable.","commonSituations":"Incomplete paste from the browser into the dashboard OAuth form; form binding not wired so the field is empty; script passing a variable before it is assigned; clipboard copy failed silently.","solutions":["Paste the full zed.dev callback URL (or its JSON) into the login form and retry","Check the UI/state binding so the input variable actually contains the pasted value before calling","Validate non-empty input client-side before invoking parseZedCallbackPayload","If automating, ensure the callback URL was captured completely (query string included)"],"exampleFix":"// before\nconst { userId, encryptedAccessToken } = parseZedCallbackPayload(input.value);\n// after\nif (!input.value?.trim()) throw new Error(\"Paste the Zed callback URL first\");\nconst { userId, encryptedAccessToken } = parseZedCallbackPayload(input.value);","handlingStrategy":"validation","validationCode":"function hasZedCallbackInput(input) {\n  return typeof input === \"string\" && input.trim().length > 0;\n}\nif (!hasZedCallbackInput(pasted)) alert(\"Paste the zed.dev callback URL first\");","typeGuard":null,"tryCatchPattern":"try {\n  const { userId, encryptedAccessToken } = parseZedCallbackPayload(pasted);\n} catch (e) {\n  if (/Missing Zed callback URL/.test(e.message)) {\n    return showFormError(\"Callback URL is required\");\n  }\n  throw e;\n}","preventionTips":["Require the callback field in the login UI before submission","Trim and check non-empty before parsing","Distinguish empty input (this error) from malformed input (parse errors)","Capture the full URL including query parameters when copying"],"tags":["zed","oauth","validation","empty-input"],"backgroundTag":"missing-callback-payload","analyzedSha":"90b52e06ffd666b7929554211474d01588f6b1f8","analyzedAt":"2026-08-30T21:05:45.952Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}