JuliusBrussee/caveman · error

cacheengine: invalid object close

Error message

cacheengine: invalid object close

What it means

Thrown by inspectUniqueJSONValue when, after consuming all members of an object (decoder.More() returned false), the next token is not '}'. In a well-formed stream this cannot happen; it indicates truncated or malformed JSON that the streaming decoder walked past, or corrupted decoder state.

Source

Thrown at cacheengine/native.go:509

				return false, err
			}
			key, ok := keyToken.(string)
			if !ok || seen[key] {
				return false, errors.New("cacheengine: duplicate or invalid object key")
			}
			seen[key] = true
			matched := cacheMarkerAt(provider, path, key)
			path = append(path, key)
			childFound, err := inspectUniqueJSONValue(decoder, false, depth+1, provider, path)
			path = path[:len(path)-1]
			if err != nil {
				return false, err
			}
			found = found || matched || childFound
		}
		closing, err := decoder.Token()
		if err != nil || closing != json.Delim('}') {
			return false, errors.New("cacheengine: invalid object close")
		}
		return found, nil
	case '[':
		if root {
			return false, errors.New("cacheengine: request root must be object")
		}
		found := false
		path = append(path, "*")
		for decoder.More() {
			childFound, err := inspectUniqueJSONValue(decoder, false, depth+1, provider, path)
			if err != nil {
				return false, err
			}
			found = found || childFound
		}
		closing, err := decoder.Token()
		if err != nil || closing != json.Delim(']') {
			return false, errors.New("cacheengine: invalid array close")

View on GitHub (pinned to 27d5a3981a)

Solutions

  1. Validate the body with a strict full-document json.Unmarshal/Valid check before sending to the engine
  2. Fix body-rewriting middleware to re-marshal rather than byte-slice editing
  3. Ensure no upstream truncates the body (content-length mismatches, log-redaction that cuts tails)

Example fix

// before
body := strings.Replace(string(raw), "long_field_to_strip", "", 1) // can leave broken/truncated JSON

// after
var m map[string]any
json.Unmarshal(raw, &m)
delete(m, "long_field_to_strip")
body, _ := json.Marshal(m)
Defensive patterns

Strategy: validation

Validate before calling

if !json.Valid(body) { return errors.New("invalid JSON body") }

Type guard

// n/a

Prevention

When it happens

Trigger: A body whose object is not properly closed, e.g. '{"a":1' or '{"a":1]' — combined with the walker's structure; in practice this surfaces with truncated bodies or hand-assembled JSON where the closing brace is missing/replaced.

Common situations: Truncated request bodies (a size cap cutting the tail, or a partial write); hand-built JSON in tests missing the closing brace; a body-editing middleware that drops trailing bytes (e.g. when stripping a field by slicing).

Related errors


AI-assisted analysis of JuliusBrussee/caveman@27d5a3981a (2026-08-15). Data as JSON: /api/errors/50bb481e7fbf4c33. Report an issue: GitHub.