Help us shape the future of Go! Take the 2026 Go Developer Survey

strictjson

package
v0.25.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 26, 2026 License: Apache-2.0 Imports: 14 Imported by: 0

Documentation

Overview

Package strictjson decodes JSON so that what a reader sees in the text is exactly what the decoded value holds. encoding/json accepts a duplicate key and keeps the last value, matches keys case-insensitively, ignores unknown fields, and rewrites invalid UTF-8 and escaped lone surrogates to U+FFFD; each lets one text mean a value other than the one it shows. The checks here reject all of them, token by token against the target type, before encoding/json decodes.

The audit package reads proof artifacts with it (audit.UnmarshalStrict) and the agent package reads tool arguments and typed answers with it, which also requires every field schema.For lists as required.

Index

Constants

View Source
const MaxDepth = 128

MaxDepth is the deepest nesting of arrays and objects the structure of a document may have. The deepest document bide reads from its fixtures, examples, golden exports and test data nests 5 levels (the journal records in agent/testdata), and the deepest any test reads is 7; 128 leaves an order of magnitude of headroom, and is the nesting past which a document is an attack, not data. JSON kept verbatim (json.RawMessage, as a journal keeps a tool call's input and a tool's result, whatever a model or a tool made it) is not structure bide defines, so it is held to MaxVerbatimDepth instead: a record carrying a deep tool input must stay readable.

View Source
const MaxVerbatimDepth = 10000

MaxVerbatimDepth is the deepest nesting any document may have, structure and verbatim JSON together: about 10000, encoding/json's own limit (a verbatim value inside a journal record counts the record's own wrapper, so 9991 levels of one are read and 10000 are not). Check refuses a deeper document before any decoder runs, so no reader spends time or memory on it.

Variables

View Source
var ErrTrailingData = errors.New("trailing data after the value")

ErrTrailingData reports data after the one JSON value.

Functions

func BoundedError added in v0.22.0

func BoundedError(err error) error

BoundedError is err with its text cut to maxMessage characters (and Go-escaped where it is cut), keeping err for errors.Is and errors.As. nil and short errors come back as they are.

func BoundedErrorN added in v0.22.0

func BoundedErrorN(err error, max int) error

BoundedErrorN is BoundedError with a limit of max characters.

func Check

func Check(data []byte, t reflect.Type, opts *Options) error

Check consumes the one JSON value in data, checking it against t, and returns ErrTrailingData if anything but whitespace follows. An object decoded into a struct may use only that struct's exact JSON field names, each at most once, and must include each required one, with a value other than null unless the field takes null (Field.NullOK); every other object (a map, raw JSON, a type with its own UnmarshalJSON, an interface) is checked for duplicate names only, at any depth. Strings decoded into Go must have one spelling: no escaped lone surrogate, and in a []byte, base64 that is the standard encoding of its bytes. JSON kept verbatim (json.RawMessage) is checked for duplicate names only.

func CheckValue

func CheckValue(raw []byte, t reflect.Type, at string, opts *Options) error

CheckValue checks the first JSON value in raw against t, as Check does, naming path in its errors. It does not look past that value.

func ExactFields

func ExactFields(t reflect.Type) map[string]Field

ExactFields returns the exact JSON names encoding/json decodes into struct type t, with each field's type, by encoding/json's own rules: exported fields by tag name or Go name (a "-" tag is skipped), and the fields of an untagged embedded struct promoted into t. When several fields claim one name, the shallowest wins, and at equal depth a tagged field wins over an untagged one. A name still claimed by several fields is one encoding/json ignores; it is kept here, and the decode that follows (DisallowUnknownFields) rejects it. No field is required, and every field takes null.

func Quote added in v0.22.0

func Quote(s string) string

Quote is s as Go quotes it (so a control character or an escape sequence is written out, not sent to a terminal), cut to maxQuoted characters with "..." when longer. Errors name text from the document through it, never raw.

func SchemaFields

func SchemaFields(t reflect.Type) map[string]Field

SchemaFields returns the names struct type t accepts as schema.For describes them: the fields encoding/json reads (jsonfields.Of), each required exactly when the schema lists it as required. A required field takes null only when its schema admits any value (For leaves an interface, json.RawMessage, or a json.Unmarshaler other than time.Time unconstrained); otherwise encoding/json would read null as the zero value, one the document never gave. An optional field takes null (OpenAI strict mode sends it). A type jsonfields cannot resolve accepts no names.

func Unmarshal

func Unmarshal(data []byte, v any, opts *Options) error

Unmarshal checks data against v's type (see Check) and decodes it into v with encoding/json, which then rejects any name the check let through that is not a field (unless Options.AllowUnknown, when it ignores such names). Invalid UTF-8 anywhere in data is an error.

Types

type Field

type Field struct {
	Type     reflect.Type
	Required bool
	NullOK   bool
}

Field is one name a struct accepts: the type its value decodes into, whether a document must include it, and whether it may be null.

type Options

type Options struct {
	// Fields returns the names struct type t accepts, each exactly as spelled. Nil means
	// ExactFields.
	Fields func(t reflect.Type) map[string]Field
	// Shapes maps a type to the type its JSON is checked against instead: for a type whose own
	// UnmarshalJSON matches names loosely, its wire shape.
	Shapes map[reflect.Type]reflect.Type
	// Hooks maps a type to a check of its own: the value is consumed (checked for duplicate
	// names only) and its raw text, with the path to it, is handed to the hook.
	Hooks map[reflect.Type]func(raw []byte, path string) error
	// AllowUnknown lets an object decoded into a struct carry names the struct does not have, as a
	// document written by a later version does. Such a name must not be a case variant of a name
	// the struct has ("Kind" beside a "kind" field), which encoding/json would read into that
	// field; its value is checked like any value decoded into Go: no duplicate names at any depth
	// and no escaped lone surrogate.
	AllowUnknown bool
}

Options configure a check.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL