plandex-ai/plandex · error

unsupported data type: %T

Error message

unsupported data type: %T

What it means

PlanSettings' Scan method accepts only []byte and string, unmarshaling JSON into the struct; any other driver.Value (nil/NULL, numeric, etc.) produces this error. Like errors 773/774/777/778 it guards a JSON-in-DB column.

Source

Thrown at app/shared/plan_model_settings.go:96

	p.ModelPack = nil
}

func (p *PlanSettings) SetCustomModelPack(modelPack *ModelPack) {
	p.ModelPackName = ""
	p.ModelPack = modelPack
}

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

func (p PlanSettings) Value() (driver.Value, error) {
	return json.Marshal(p)
}

func (ps PlanSettings) GetPlannerMaxTokens() int {
	modelPack := ps.GetModelPack()
	planner := modelPack.Planner
	fallback := planner.GetFinalLargeContextFallback()
	baseConfig := fallback.GetSharedBaseConfig(&ps)
	return baseConfig.MaxTokens
}

func (ps PlanSettings) GetPlannerMaxReservedOutputTokens() int {
	modelPack := ps.GetModelPack()
	planner := modelPack.Planner

View on GitHub (pinned to e2d772072e)

Solutions

  1. COALESCE the column in SQL so NULL is never passed to Scan.
  2. Add a nil case assigning an empty PlanSettings before the default branch.
  3. Keep the column as JSONB/TEXT so drivers deliver []byte/string.
  4. Re-test after driver/ORM upgrades for changed JSON decoding types.

Example fix

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

Strategy: type-guard

Validate before calling

var ps PlanSettings
err := db.QueryRow("SELECT COALESCE(plan_model_settings, '{}'::jsonb) FROM plans WHERE id=$1", planId).Scan(&ps)

Type guard

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

Try / catch

var ps PlanSettings
if err := rows.Scan(&ps); err != nil {
    if strings.Contains(err.Error(), "unsupported data type") {
        ps = PlanSettings{} // zero-value fallback
    } else {
        return err
    }
}

Prevention

When it happens

Trigger: Scanning a NULL plan_model_settings column (nil hits default); driver returning a non-text Go type for the column; mapping Scan to a mismatched column type.

Common situations: Old rows predating the settings column; schema changes or defaults dropped in migration; driver upgrades changing how JSON columns are delivered to Scanner implementations.

Related errors


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