siyuan-note/siyuan · error

invalid config.

Error message

invalid config.%s: %v

What it means

unmarshalCapabilityJSON decodes the serialized JSON of a named config field into its Go target struct. If json.Unmarshal fails (the JSON does not fit the target's types), this error is returned with the field name. The value serializes fine but has the wrong shape or types for the capability config.

Solutions

  1. Match the documented ToolEffects shape: e.g. { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: true }
  2. Use boolean values for hint fields, not strings or numbers
  3. Read the wrapped invalid config.<field> message to see the exact decode failure
  4. Compare against a working plugin sample's config

Example fix

// before
config.effects = { run: "readonly" }

// after
config.effects = { run: { readOnlyHint: true, destructiveHint: false } }
Defensive patterns

Strategy: validation

Validate before calling

function validateEffects(effects) {
  return Object.entries(effects || {}).every(([k, v]) =>
    k && typeof v === "object" && v !== null &&
    Object.values(v).every((x) => typeof x === "boolean"));
}

Type guard

const isToolEffects = (v) => v !== null && typeof v === "object" && !Array.isArray(v) && Object.values(v).every((x) => typeof x === "boolean");

Try / catch

try {
  registerCapability(config);
} catch (e) {
  if (String(e).includes("invalid config.")) {
    console.error("Capability config shape/type mismatch", e);
  }
}

Prevention

When it happens

Trigger: config.effects or config.actionEffects has wrong-typed members, e.g. effects: {run: "readonly"} instead of an effects object, or actionEffects values missing expected fields / with wrong types like numeric hints.

Common situations: Authors guess the config shape instead of following the ToolEffects struct; using string flags where booleans are expected; nesting the map one level too deep or shallow.

Related errors


AI-assisted analysis of siyuan-note/siyuan@9f775e8a12 (2026-09-19). Data as JSON: /api/errors/17b779faa1b5999e. Report an issue: GitHub.

Appendix: source

Thrown at kernel/plugin/api_agent.go:305

	actionEffects := map[string]tools.ToolEffects{}
	if err := unmarshalCapabilityJSON(rt, value, &actionEffects, "actionEffects"); err != nil {
		return nil, err
	}
	for action := range actionEffects {
		if strings.TrimSpace(action) == "" {
			return nil, fmt.Errorf("config.actionEffects contains an empty action")
		}
	}
	return actionEffects, nil
}

func unmarshalCapabilityJSON(rt *goja.Runtime, value goja.Value, target any, field string) error {
	jsonValue, err := value.ToObject(rt).MarshalJSON()
	if err != nil {
		return fmt.Errorf("failed to serialize config.%s: %v", field, err)
	}
	if err = json.Unmarshal(jsonValue, target); err != nil {
		return fmt.Errorf("invalid config.%s: %v", field, err)
	}
	return nil
}

View on GitHub (pinned to 9f775e8a12)