plandex-ai/plandex · error

unsupported data type: %T

Error message

unsupported data type: %T

What it means

ModelRoleConfig implements sql.Scanner; its Scan method only accepts []byte and string (JSON text from the DB column) and rejects any other driver.Value type with this error. It fires when the database driver hands Scan a value type it does not handle, typically nil/NULL or a non-text type.

Source

Thrown at app/shared/ai_models_data_models.go:669

	customModel := customModels[m.ModelId]
	if customModel != nil {
		return &customModel.BaseModelShared
	}

	return nil
}

func (m *ModelRoleConfig) Scan(src interface{}) error {
	if src == nil {
		return nil
	}
	switch s := src.(type) {
	case []byte:
		return json.Unmarshal(s, m)
	case string:
		return json.Unmarshal([]byte(s), m)
	default:
		return fmt.Errorf("unsupported data type: %T", src)
	}
}

func (m ModelRoleConfig) Value() (driver.Value, error) {
	return json.Marshal(m)
}

type PlannerRoleConfig struct {
	ModelRoleConfig
	PlannerModelConfig
}

func (p *PlannerRoleConfig) Scan(src interface{}) error {
	if src == nil {
		return nil
	}
	switch s := src.(type) {
	case []byte:

View on GitHub (pinned to e2d772072e)

Solutions

  1. COALESCE the column in SQL (e.g. SELECT COALESCE(model_role_config, '{}')) so NULL never reaches Scan.
  2. Add a nil case to the switch: if src == nil { *m = ModelRoleConfig{}; return nil }.
  3. Ensure the column type is JSONB/TEXT so the driver delivers []byte or string.
  4. Check the driver/ORM version for changed column decoding behavior.

Example fix

// before
switch s := src.(type) {
case []byte:
    return json.Unmarshal(s, m)
case string:
    return json.Unmarshal([]byte(s), m)
default:
    return fmt.Errorf("unsupported data type: %T", src)
}
// after
switch s := src.(type) {
case nil:
    *m = ModelRoleConfig{}
    return nil
case []byte:
    return json.Unmarshal(s, m)
case string:
    return json.Unmarshal([]byte(s), m)
default:
    return fmt.Errorf("unsupported data type: %T", src)
}
Defensive patterns

Strategy: type-guard

Validate before calling

// ensure the column is never NULL in SQL
var cfg ModelRoleConfig
err := db.QueryRow("SELECT COALESCE(model_role_config, '{}'::jsonb) FROM orgs WHERE id=$1", orgId).Scan(&cfg)

Type guard

func scanableJSON(src any) bool {
    switch src.(type) {
    case []byte, string:
        return true
    default:
        return false
    }
}

Try / catch

var cfg ModelRoleConfig
err := rows.Scan(&cfg)
if err != nil {
    var typeErr *json.UnmarshalTypeError
    if strings.Contains(err.Error(), "unsupported data type") {
        cfg = ModelRoleConfig{} // fall back to zero value
    } else {
        return err
    }
}

Prevention

When it happens

Trigger: Scanning a NULL model_role_config column into a ModelRoleConfig field (driver passes nil, which hits default); a driver returning []int or other unusual types for the column.

Common situations: Reading a row where the JSONB config column is NULL without COALESCE; using a driver or ORM that decodes JSON columns into types other than []byte/string; direct raw queries returning typed columns.

Related errors


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