Tencent/WeKnora · error

marshal credentials: %w

Error message

marshal credentials: %w

What it means

parseConfig marshals config.Credentials (a map[string]interface{}) to JSON before decoding it into the connector's Config struct. If json.Marshal of the credentials fails, the error is wrapped as "marshal credentials: %w". Marshaling a map[string]interface{} rarely fails, but it can when credentials contain values unsupported by the JSON encoder (e.g. NaN/Inf floats, channels, funcs) injected by a plugin or upstream decoder.

Source

Thrown at internal/datasource/connector/rss/types.go:61

// because they may carry secrets that must be encrypted at rest. Credentials
// may still carry feed_urls for backward compatibility with older rows.
type Config struct {
	// FeedURLs is a newline- or comma-separated list of feed URLs.
	FeedURLs string `json:"feed_urls"`

	// AuthHeaders is an optional newline-separated list of custom request
	// headers in "Name: Value" form, applied only to feed fetches.
	AuthHeaders string `json:"auth_headers,omitempty"`
}

// parseConfig extracts and validates RSS configuration.
func parseConfig(config *types.DataSourceConfig) (*Config, error) {
	if config == nil {
		return nil, fmt.Errorf("%w: config is nil", datasource.ErrInvalidConfig)
	}
	credBytes, err := json.Marshal(config.Credentials)
	if err != nil {
		return nil, fmt.Errorf("marshal credentials: %w", err)
	}
	var cfg Config
	if err := json.Unmarshal(credBytes, &cfg); err != nil {
		return nil, fmt.Errorf("parse rss credentials: %w", err)
	}
	if urls := feedURLsFromSettings(config.Settings); urls != "" {
		cfg.FeedURLs = urls
	}
	if len(cfg.feedURLList()) == 0 {
		return nil, fmt.Errorf("%w: feed_urls is required", datasource.ErrInvalidCredentials)
	}
	return &cfg, nil
}

func feedURLsFromSettings(settings map[string]interface{}) string {
	if len(settings) == 0 {
		return ""
	}

View on GitHub (pinned to 988cbb0330)

Solutions

  1. Log/inspect the credentials map (redacting secrets) and remove or fix the non-JSON-serializable value.
  2. Fix the upstream code that populates Credentials so only JSON-safe types (string, bool, numbers, nested maps/slices) are inserted.
  3. If numbers are suspect, sanitize NaN/Inf to 0 or a string before assigning Credentials.
  4. Update the saved datasource record in the database so it stores valid JSON credentials.

Example fix

// before
cfg.Credentials["timeout"] = math.NaN() // marshal fails
// after
t := cfg.Credentials["timeout"]
if f, ok := t.(float64); ok && (math.IsNaN(f) || math.IsInf(f, 0)) {
    cfg.Credentials["timeout"] = 0
}
Defensive patterns

Strategy: validation

Validate before calling

if _, err := json.Marshal(config.Credentials); err != nil {
    return fmt.Errorf("credentials are not JSON-serializable: %w", err)
}

Type guard

func jsonSafe(v interface{}) bool {
    switch v.(type) {
    case string, bool, int, int64, float64, map[string]interface{}, []interface{}, nil:
        return true
    }
    return false
}

Try / catch

cfg, err := parseConfig(config)
if err != nil && strings.HasPrefix(err.Error(), "marshal credentials") {
    // re-save or repair the datasource credentials payload
    return err
}

Prevention

When it happens

Trigger: config.Credentials contains a value type that encoding/json cannot marshal — e.g. a float NaN/Inf produced by an upstream computation, a channel/func value smuggled into the map via a custom decoder, or a cyclic structure if the map type ever changes.

Common situations: Credentials built programmatically from parsed YAML/ini where numbers decoded to NaN; custom secret resolvers injecting non-JSON-serializable objects; a corrupt in-memory credentials map.

Understand the failure class

Background: "JSON serialization failed", "not JSON serializable", "Failed to serialize": why JSON marshaling errors happen and how to fix them — this error's family across 46 libraries.

Related errors


AI-assisted analysis of Tencent/WeKnora@988cbb0330 (2026-09-02). Data as JSON: /api/errors/de6e98efbc5186cf. Report an issue: GitHub.