{"record":{"id":"cd8a47c41d253c29","repo":"farion1231/cc-switch","slug":"label-must-be-an-absolute-http-or-https-url","errorCode":null,"errorMessage":"{{label}} must be an absolute HTTP or HTTPS URL","messagePattern":"(.+?)\\} must be an absolute HTTP or HTTPS URL","errorType":"validation","errorClass":"PiFormValidationError","httpStatus":null,"severity":"error","filePath":"src/components/providers/forms/PiProviderForm.tsx","lineNumber":134,"sourceCode":"  constructor(\n    message: string,\n    readonly fieldSelector?: string,\n    readonly revealAdvanced = false,\n  ) {\n    super(message);\n    this.name = \"PiFormValidationError\";\n  }\n}\n\nfunction validatePiField<T>(\n  operation: () => T,\n  fieldSelector: string,\n  revealAdvanced = false,\n): T {\n  try {\n    return operation();\n  } catch (error) {\n    throw new PiFormValidationError(\n      error instanceof Error ? error.message : String(error),\n      fieldSelector,\n      revealAdvanced,\n    );\n  }\n}\n\nfunction objectWithout(\n  value: Record<string, unknown>,\n  denied: Set<string>,\n): Record<string, unknown> {\n  return Object.fromEntries(\n    Object.entries(value).filter(([key]) => !denied.has(key)),\n  );\n}\n\nfunction asObject(value: unknown): Record<string, unknown> {\n  return value && typeof value === \"object\" && !Array.isArray(value)","sourceCodeStart":116,"sourceCodeEnd":152,"githubUrl":"https://github.com/farion1231/cc-switch/blob/0b5da510168914b251481654a568c3ffacd62cf4/src/components/providers/forms/PiProviderForm.tsx#L116-L152","documentation":"validatePiField is the Pi provider form's error wrapper: it runs a validation closure and re-wraps any failure into PiFormValidationError, preserving the inner message while attaching fieldSelector and revealAdvanced so the form can expand and focus the offending advanced field. With '{{label}} must be an absolute HTTP or HTTPS URL' it originates from submit-time validation of the provider Base URL (target '#pi-provider-base-url', advanced section revealed); the label is i18n-interpolated from pi.form.absoluteHttpUrlRequired with the Base URL label.","triggerScenarios":"Submitting the Pi provider form while baseUrl fails validateAbsoluteHttpUrl — unparseable or non-http(s) — during the config-building pass that also validates per-model fields.","commonSituations":"User types 'api.example.com/v1' without a scheme; copies a ws:// endpoint from another tool; clipboard paste includes leading whitespace.","solutions":["Enter the Base URL as an absolute http:// or https:// URL","Auto-prefix https:// when the user typed a bare host","Validate on blur with the same validateAbsoluteHttpUrl logic so submit never surprises the user"],"exampleFix":"// before (form state)\nbaseUrl: 'api.openrouter.ai/api/v1'\n\n// after (form state)\nbaseUrl: 'https://openrouter.ai/api/v1'","handlingStrategy":"validation","validationCode":"function isValidBaseUrl(value: string): boolean {\n  try {\n    const u = new URL(value.trim());\n    return u.protocol === 'http:' || u.protocol === 'https:';\n  } catch {\n    return false;\n  }\n}\nif (baseUrl.trim() && !isValidBaseUrl(baseUrl)) {\n  // mark the Base URL advanced field before submit\n}","typeGuard":null,"tryCatchPattern":"try {\n  buildProviderConfig(form);\n} catch (error) {\n  if (error instanceof PiFormValidationError) {\n    // error.fieldSelector targets the input; error.revealAdvanced expands its section\n    focusField(error.fieldSelector, error.revealAdvanced);\n    showFormError(error.message);\n  } else {\n    throw error;\n  }\n}","preventionTips":["Auto-prefix https:// to bare hosts on blur","Validate the URL while the user types, not only at submit","Always handle PiFormValidationError via fieldSelector/revealAdvanced in form code"],"tags":["pi","form-validation","url","i18n"],"backgroundTag":"invalid-base-url","analyzedSha":"0b5da510168914b251481654a568c3ffacd62cf4","analyzedAt":"2026-08-20T14:29:00.113Z","contentChangedAt":"2026-08-20T14:29:00.113Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}