plandex-ai/plandex · error

error marshalling json: %w

Error message

error marshalling json: %w

What it means

After stripping the top-level $schema key, validateJSON re-marshals the object back to bytes for the schema validator. This error means json.Marshal of the cleaned map failed — extremely rare for map[string]interface{} input derived from valid JSON, but possible with values the encoder cannot handle (e.g. channels, funcs injected programmatically).

Source

Thrown at app/cli/schema/schemas.go:57

func ValidateModelPackInlineJSON(jsonData []byte) (shared.ClientModelPackSchemaRoles, error) {
	return validateJSON[shared.ClientModelPackSchemaRoles](jsonData, SchemaPathModelPackInline)
}

func validateJSON[T any](jsonData []byte, schemaPath SchemaPath) (T, error) {
	var zero T

	// strip meta-keywords that break additionalProperties ──
	var tmp interface{}
	if err := json.Unmarshal(jsonData, &tmp); err != nil {
		return zero, fmt.Errorf("invalid json: %w", err)
	}
	if obj, ok := tmp.(map[string]interface{}); ok {
		delete(obj, "$schema") // ignore top-level $schema
		var err error
		jsonData, err = json.Marshal(obj)
		if err != nil {
			return zero, fmt.Errorf("error marshalling json: %w", err)
		}
	}

	schemaLoader := newEmbeddedSchemaLoader(schemaPath)
	documentLoader := gojsonschema.NewBytesLoader(jsonData)

	result, err := gojsonschema.Validate(schemaLoader, documentLoader)
	if err != nil {
		return zero, err
	}
	if !result.Valid() {
		var msgs []string
		for _, d := range result.Errors() {
			msgs = append(msgs, "• "+d.String())
		}
		return zero, errors.New(strings.Join(msgs, "\n"))
	}

View on GitHub (pinned to e2d772072e)

Solutions

  1. Ensure the input originates from valid JSON bytes, not raw Go structures
  2. Check for non-serializable values injected before validation
  3. Bypass $schema stripping (omit $schema) to skip the re-marshal path
  4. Report as a bug if input is plain JSON and this still fires

Example fix

// before
input := map[string]interface{}{"cb": func() {}} // unmarshalable
// after
input := []byte(`{"name":"my-pack"}`) // pass JSON bytes
Defensive patterns

Strategy: validation

Validate before calling

var probe interface{}
if err := json.Unmarshal(data, &probe); err != nil {
    return err
}
// round-trip check catches unmarshalable values early
if _, err := json.Marshal(probe); err != nil {
    return fmt.Errorf("round-trip marshal failed: %w", err)
}

Type guard

func roundTrips(b []byte) bool {
    var v interface{}
    if json.Unmarshal(b, &v) != nil { return false }
    _, err := json.Marshal(v)
    return err == nil
}

Try / catch

err := ValidateModelPackInlineJSON(data)
if err != nil && strings.Contains(err.Error(), "error marshalling json") {
    // input contained non-encodable values; log and report as a bug
    return fmt.Errorf("validation pre-check failed: %w", err)
}

Prevention

When it happens

Trigger: ValidateModelsInputJSON / ValidateModelPackInlineJSON receiving an object whose re-encoding fails after $schema removal — practically only when unmarshalable values were placed into the parsed structure.

Common situations: Programmatic callers constructing the input map with unsupported Go types; corruption of the decoded value by intermediary processing code.

Understand the failure class

Background: json.Marshal / "failed to marshal" errors in Go: why "unsupported type" happens and how to fix it — this error's family across 22 libraries.

Related errors


AI-assisted analysis of plandex-ai/plandex@e2d772072e (2026-09-05). Data as JSON: /api/errors/99a6f967e3edd9a0. Report an issue: GitHub.