Skip to content

fix(configuration): explain the numeric last label refusal on model baseUrl - #2436

Merged
freeqaz merged 1 commit into
mainfrom
fix-1346
Oct 14, 2026
Merged

freeqaz merged 1 commit into
mainfrom
fix-1346

Conversation

@freeqaz

@freeqaz freeqaz commented Oct 14, 2026

Copy link
Copy Markdown
Collaborator

Problem

A model provider baseUrl whose host ends in a numeric or 0x label (https://api.123/v1, https://api.0x10/v1, https://999.1.2.3/v1, https://1.2.3.4.5/v1, https://0.0.0.08/v1) is refused on Configuration create and Preset save with Configuration field /models/providers/<p>/baseUrl must be an absolute http or https URL. The value is an absolute https URL. The real reason is that the URL parser reads such a host as IPv4 and rejects it, so the message gives the user nothing to change.

Change

  • packages/occ/src/model-provider-settings.ts: when a baseUrl is refused, refusedForNumericLastLabel checks whether its host (as written, Preset variables filled as the baseUrl rule fills them with a name) ends in a numeric or 0x label, and whether the same text with that label replaced by a name is accepted. Only then the refusal uses the new baseUrlNumericHost message; every other refusal keeps the general or missing-// message. Values with ${VAR} references and non-string values are unchanged.
  • packages/occ/src/errors.ts: the new message appends the sentence fix(gateway): refuse routing hostnames that parse as another address #2387 uses for gateway routing hostnames: A numeric or 0x last label parses as IPv4; use four decimal octets from 0 to 255 without leading zeros. The message names the field and never the value.
  • docs/reference/configuration.md: one clause on the hint.
  • The other save-time URL fields (proxy, channel proxy, MCP, plugin URLs in model-auth.ts) do not refuse an unparsable host, so they have no generic parse-failure message to change.

No behavior change: the same inputs are accepted and refused before and after; only the message text differs.

Verification

  • Differential, origin/main vs this branch, validateModelProviderSettings over 120,174 cases: the five values above, trailing dots, 0X, ports, userinfo, query/fragment/backslash, tabs and surrounding spaces, percent-encoded and fullwidth digits, valid names, dotted quads, shorthand IPv4 (127.1, 0x10), IPv6 (valid and invalid), garbage, ${VAR} forms, non-string values, Preset literals, and 60,000 random URL-ish strings, at provider and model level. 0 divergences in accept/refuse, error class or field path; 2,692 messages gained only the hint. Kept the general message: https://api.123:99999/v1, https://a b.123/v1, https://api.%31%32%33/v1, ftp://api.123/v1, not a url, https:///v1.
  • New rows in tests/integration/configuration-controller.test.mjs (Configuration create: provider and model baseUrl, 0x, out-of-range octet, five labels, leading-zero octet with a trailing dot; Preset save: literal host with a path variable, model baseUrl). With main's source, the test fails on the first new row, and each new row's input gives main's general message (checked per row). One control row, https://api.123:99999/v1, keeps the general message.
  • The two touched tests 20/20 at 2 CPUs; full configuration-controller.test.mjs and occ-api.test.mjs 299/299; tsc --build clean; eslint and prettier clean on touched files.
  • Open PRs touching the same files (feat(plugins): let administrators approve pinned plugin releases #2398, fix: prepare native admin access on the first Agent deployment #2259, Enable dedicated OpenClaw from Console with pinned native runtime #1685): no new conflicted files against this branch beyond what main already causes.

Risks

Low. Message-only change for an input set that was already refused; the hint check runs only on the refusal path, in time linear in the value's length.

…aseUrl

A model provider baseUrl whose host ends in a numeric or 0x label
(https://api.123/v1, https://999.1.2.3/v1) is refused at save because
the URL parser reads the host as IPv4 and rejects it, but the message
only said the value must be an absolute http or https URL, which it is.

When the only reason a refused baseUrl fails to parse is that last
label (the same text with a name there is accepted), the refusal now
adds the gateway routing hint: a numeric or 0x last label parses as
IPv4; use four decimal octets from 0 to 255 without leading zeros.
Other refusals keep the general message. The same inputs are accepted
and refused as before; only the message changes (finding 1346).
@freeqaz
freeqaz requested a review from a team as a code owner October 14, 2026 14:54
@clawsweeper

clawsweeper Bot commented Oct 14, 2026 •

Copy link
Copy Markdown
Contributor

🦞👀
ClawSweeper picked this up.

Pull request received. I will update this pull request when review starts.

ClawSweeper review blocked

Automated review did not run, so no review verdict was produced.

Reason: The input-safety check rejected material in this revision. No detected value, path, or scanner output is reproduced here.

Automatic review is on hold, including after source changes. Request a fresh re-review after resolving the failure; maintainers can also release the hold through an intentional scanner-policy update.

Next step: If this is a genuine credential, remove and rotate it. If it is an intentional test fixture, a maintainer must review and qualify it.

View the workflow run.

@freeqaz
freeqaz merged commit 6d04d87 into main Oct 14, 2026
40 of 42 checks passed
@freeqaz
freeqaz deleted the fix-1346 branch October 14, 2026 15:07

This branch had an error being deployed

1 failed deployment
integration-qa-pr — 775fb395 Deployed Oct 14, 2026 by freeqaz via QA advisory (compose) #894
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant