{"record":{"id":"b02559e249429272","repo":"decolua/9router","slug":"invalid-callback-url-format","errorCode":null,"errorMessage":"Invalid callback URL format","messagePattern":"Invalid callback URL format","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"src/shared/components/KiroSocialOAuthModal.js","lineNumber":70,"sourceCode":"        setError(err.message);\n        setStep(\"error\");\n      }\n    };\n\n    initAuth();\n  }, [isOpen, provider]);\n\n  const handleManualSubmit = async () => {\n    try {\n      setError(null);\n      \n      // Parse callback URL - can be either kiro:// or http://localhost format\n      let url;\n      try {\n        url = new URL(callbackUrl);\n      } catch (e) {\n        // If URL parsing fails, might be malformed\n        throw new Error(\"Invalid callback URL format\");\n      }\n\n      const code = url.searchParams.get(\"code\");\n      const state = url.searchParams.get(\"state\");\n      const errorParam = url.searchParams.get(\"error\");\n\n      if (errorParam) {\n        throw new Error(url.searchParams.get(\"error_description\") || errorParam);\n      }\n\n      if (!code) {\n        throw new Error(\"No authorization code found in URL\");\n      }\n\n      // Exchange code for tokens\n      const res = await fetch(\"/api/oauth/kiro/social-exchange\", {\n        method: \"POST\",\n        headers: { \"Content-Type\": \"application/json\" },","sourceCodeStart":52,"sourceCodeEnd":88,"githubUrl":"https://github.com/decolua/9router/blob/90b52e06ffd666b7929554211474d01588f6b1f8/src/shared/components/KiroSocialOAuthModal.js#L52-L88","documentation":"handleManualSubmit in KiroSocialOAuthModal parses the manually pasted callback URL with `new URL(callbackUrl)`; when the string is not a valid absolute URL the constructor throws and this wrapper converts it into a readable Error. The modal accepts either `kiro://...` or `http://localhost...` callback shapes, both of which must still be parseable by the URL constructor (kiro:// works because it has scheme + rest).","triggerScenarios":"User pastes something into the manual callback input that `new URL()` cannot parse: an empty string, a bare authorization code, a URL missing its scheme (e.g. \"localhost:PORT/callback?code=...\" is actually misparsed), truncated copy/paste, or text with stray whitespace/newlines.","commonSituations":"Copying only part of the callback URL from the browser address bar; pasting the code alone instead of the full URL; the kiro:// deep link got mangled by the terminal or chat client; leading/trailing whitespace from copying.","solutions":["Re-copy the entire callback URL, including the scheme (kiro:// or http://), and paste it again.","Trim whitespace: paste after `.trim()`-ing the input, or check the raw string in devtools.","If your deep link doesn't include a scheme, prepend one manually (e.g. kiro://callback?code=...&state=...).","Verify the URL contains `code` and `state` query params — if you only got the code, this error may appear first for malformed input."],"exampleFix":"// before\nlet url;\ntry {\n  url = new URL(callbackUrl);\n} catch (e) {\n  throw new Error(\"Invalid callback URL format\");\n}\n// after\nlet url;\ntry {\n  url = new URL(callbackUrl.trim());\n} catch (e) {\n  throw new Error(`Invalid callback URL format: \"${callbackUrl.slice(0, 80)}\" (expected kiro://... or http://localhost/...?code=...)`);\n}","handlingStrategy":"validation","validationCode":"function isValidCallbackUrl(s) {\n  if (typeof s !== \"string\") return false;\n  try {\n    const u = new URL(s.trim());\n    return u.protocol === \"kiro:\" || (u.protocol === \"http:\" || u.protocol === \"https:\");\n  } catch {\n    return false;\n  }\n}\n// call before handleManualSubmit\nif (!isValidCallbackUrl(callbackUrl)) {\n  setError(\"Paste the full callback URL (kiro://... or http://localhost/...?code=...)\");\n  return;\n}","typeGuard":"function asParsedUrl(value) {\n  try { const u = new URL(String(value).trim()); return /^kiro:|^https?:$/.test(u.protocol) ? u : null; }\n  catch { return null; }\n}","tryCatchPattern":"try {\n  const url = asParsedUrl(callbackUrl);\n  if (!url) throw new Error(`Invalid callback URL format: \"${String(callbackUrl).slice(0, 80)}\"`);\n  // proceed\n} catch (err) {\n  setError(err.message);\n}","preventionTips":["Copy the complete redirected URL including scheme and query string.","Trim whitespace/newlines before parsing.","Prefer deep-link capture over manual paste where possible.","Show a placeholder in the input showing the expected format."],"tags":["validation","url-parsing","oauth","kiro"],"backgroundTag":"invalid-url-format","analyzedSha":"90b52e06ffd666b7929554211474d01588f6b1f8","analyzedAt":"2026-08-30T21:05:45.952Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}