Skip to content
skyl

Request.Validate

Reports whether the request is well-formed, before any round trip.

Validate is what makes a malformed request fail locally instead of costing a network call. Client calls it before dispatching, so you rarely call it yourself — but it is exported, and useful at a CLI boundary.

Reference#

func (r *Request) Validate() error

Returns

nil when well-formed. Otherwise an error wrapping ErrBadRequest, with a message naming the exact problem and, where relevant, the message and part index.

Caveats

  • It is nil-safe: (*Request)(nil).Validate() returns "skyl: invalid request: nil request" rather than panicking.
  • It validates structure, not semantics. The model string, the tool schema and role ordering are all deliberately unchecked.
  • Adapters may impose further requirements and reject things Validate accepts — an image URL on Gemini, for instance, which fails with ErrUnsupported.

What it rejects#

ConditionMessage
nil requestnil request
empty Modelmodel is required
empty Messagesat least one message is required
negative MaxTokensmax tokens must not be negative
unknown Rolemessage N has invalid role "x"
a message with no partsmessage N has no parts
a nil partmessage N part M is nil
an unknown part typemessage N part M has unknown type T
Image with neither Data nor URLimage needs data or a URL
Image with Data but no MediaTypeimage data needs a media type
ToolCall missing ID or Nametool call needs an ID and a name
ToolResult missing CallIDtool result needs a call ID
a Tool with no nametool N has no name
an unknown ToolChoice modeunknown tool choice mode "x"
ToolChoiceSpecific with no Nametool choice "tool" requires a name

What it deliberately does not check#

The model string. Validating it would eventually reject a model you are entitled to use. See ADR-0004.

Role ordering. Providers disagree about what is legal — a leading assistant turn, two user turns in a row — and rejecting a shape one vendor accepts would be skyl deciding something it has no business deciding.

The tool schema. JSON Schema is large and versioned, and providers accept different subsets. An invalid schema comes back as the provider's own 400, which is more specific than anything skyl could say.

An Image with both Data and URL. Ambiguous, but not structurally invalid — so it is accepted, and one of them is silently dropped by the adapter.

Usage#

Failing fast at a CLI boundary

goCompiles
if err := req.Validate(); err != nil {
	// Reject at parse time rather than after constructing a client.
	return fmt.Errorf("your request is not well-formed: %w", err)
}
if err := req.Validate(); err != nil {
	// Reject at parse time rather than after constructing a client.
	return fmt.Errorf("your request is not well-formed: %w", err)
}

Testing what it catches

goCompiles
err := (&skyl.Request{Model: "", Messages: nil}).Validate()

fmt.Println(errors.Is(err, skyl.ErrBadRequest)) // true
fmt.Println(err)                                // skyl: invalid request: model is required
err := (&skyl.Request{Model: "", Messages: nil}).Validate()

fmt.Println(errors.Is(err, skyl.ErrBadRequest)) // true
fmt.Println(err)                                // skyl: invalid request: model is required

Troubleshooting#

My request passed Validate and the provider still rejected it

Expected. Validate checks structure; the provider checks semantics. An unknown model, an invalid tool schema, or a role ordering that vendor dislikes all pass locally and fail upstream — with a message more specific than skyl could give.

I want to reject an image with both Data and URL

Validate will not, because it is ambiguous rather than invalid. Constrain it at your own boundary — two constructors instead of one struct literal:

goCompiles
func imageFromData(mediaType string, data []byte) skyl.Part {
	return skyl.Image{MediaType: mediaType, Data: data}
}
func imageFromURL(url string) skyl.Part { return skyl.Image{URL: url} }
func imageFromData(mediaType string, data []byte) skyl.Part {
	return skyl.Image{MediaType: mediaType, Data: data}
}
func imageFromURL(url string) skyl.Part { return skyl.Image{URL: url} }

Edit this page on GitHub