{"record":{"id":"c58621ab007737f2","repo":"farion1231/cc-switch","slug":"pi-form-absolutehttpurlrequired","errorCode":null,"errorMessage":"pi.form.absoluteHttpUrlRequired","messagePattern":"pi\\.form\\.absoluteHttpUrlRequired","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"warning","filePath":"src/components/providers/forms/PiProviderForm.tsx","lineNumber":227,"sourceCode":"    );\n  }\n  return false;\n}\n\nfunction stringRecord(value: Record<string, unknown>): Record<string, string> {\n  return Object.fromEntries(\n    Object.entries(value).filter(\n      (entry): entry is [string, string] => typeof entry[1] === \"string\",\n    ),\n  );\n}\n\nfunction validateAbsoluteHttpUrl(value: string, errorMessage: string): void {\n  let parsed: URL;\n  try {\n    parsed = new URL(value);\n  } catch {\n    throw new Error(errorMessage);\n  }\n  if (parsed.protocol !== \"http:\" && parsed.protocol !== \"https:\") {\n    throw new Error(errorMessage);\n  }\n}\n\nfunction positiveNumber(\n  value: string,\n  errorMessage: string,\n  fieldSelector: string,\n): number {\n  const parsed = Number(value);\n  if (value.trim() === \"\" || !Number.isFinite(parsed) || parsed <= 0) {\n    throw new PiFormValidationError(errorMessage, fieldSelector, true);\n  }\n  return parsed;\n}\n","sourceCodeStart":209,"sourceCodeEnd":245,"githubUrl":"https://github.com/farion1231/cc-switch/blob/a2e22f330273a5b6ffa87cb8b82b624601bac562/src/components/providers/forms/PiProviderForm.tsx#L209-L245","documentation":"validateAbsoluteHttpUrl in the Pi provider form throws the localized message keyed 'pi.form.absoluteHttpUrlRequired' when new URL(value) throws - the base URL is not parseable as an absolute URL at all (empty after trim, embedded spaces, or scheme-less like 'api.example.com/v1'). At the call site it is wrapped by validatePiField, which rethrows it as PiFormValidationError with fieldSelector '#pi-provider-base-url' and revealAdvanced=true. Validation only runs when the base URL field is non-empty.","triggerScenarios":"Submitting the Pi form with baseUrl 'api.example.com/v1' (no scheme), ' my url', or another value new URL() cannot parse.","commonSituations":"Users omit 'https://' when entering an API base URL; leading/trailing whitespace survives an untrimmed paste; field pre-filled from a domain-only import.","solutions":["Enter a full absolute URL including the scheme: https://api.example.com/v1","Trim the value before validation and on change","Auto-prepend https:// when no scheme is detected"],"exampleFix":"// before\nbaseUrl = \"api.example.com/v1\"; // -> pi.form.absoluteHttpUrlRequired\n\n// after\nbaseUrl = \"https://api.example.com/v1\";","handlingStrategy":"validation","validationCode":"function isParsableAbsoluteUrl(value: string): boolean {\n  try {\n    new URL(value.trim());\n    return true;\n  } catch {\n    return false;\n  }\n}\n\nconst trimmed = baseUrl.trim();\nif (trimmed && !isParsableAbsoluteUrl(trimmed)) {\n  setFieldError(\"#pi-provider-base-url\", \"Include the scheme, e.g. https://api.example.com/v1\");\n}","typeGuard":null,"tryCatchPattern":"// The call site wraps this in validatePiField, so catch PiFormValidationError\n// (not the inner plain Error) and use its fieldSelector:\ntry {\n  buildPiProviderConfig(form);\n} catch (e) {\n  if (e instanceof PiFormValidationError && e.message.includes(\"absoluteHttpUrlRequired\")) {\n    focusField(e.fieldSelector, e.revealAdvanced);\n  } else {\n    throw e;\n  }\n}","preventionTips":["Always include the scheme when entering base URLs","Trim input before validation and on paste","Auto-prepend https:// when no scheme is detected at entry time"],"tags":["form","url","validation","i18n","pi"],"backgroundTag":null,"analyzedSha":"a2e22f330273a5b6ffa87cb8b82b624601bac562","analyzedAt":"2026-08-16T03:46:07.889Z","schemaVersion":2},"datasetVersion":"2026-08-16T08:17:34.114Z"}