sipeed/picoclaw · error

no models returned by %s

Error message

no models returned by %s

What it means

picoclaw model add reached the provider's /models endpoint successfully, but the parsed list was empty. The parser deliberately treats both {"data":[]} and bare [] as valid empty results, so this means the server genuinely reported zero models — the interactive picker cannot be built from an empty list. Only hit when -m/--model is omitted.

Source

Thrown at cmd/picoclaw/internal/model/add.go:109

	stdout    io.Writer
}

func runAdd(opt addOptions) error {
	if opt.modelType != "" && opt.modelType != "openai-compatible" {
		return fmt.Errorf("unsupported --type %q (only 'openai-compatible' is supported)", opt.modelType)
	}
	if opt.alias == "" {
		opt.alias = defaultAliasName
	}

	selected := opt.modelID
	if selected == "" {
		entries, err := fetchOpenAIModels(opt.apiBase, opt.apiKey)
		if err != nil {
			return fmt.Errorf("fetch models: %w", err)
		}
		if len(entries) == 0 {
			return fmt.Errorf("no models returned by %s", opt.apiBase)
		}
		selected, err = pickModel(opt.stdin, opt.stdout, entries)
		if err != nil {
			return err
		}
	}

	return upsertModelDefault(opt.apiBase, opt.apiKey, opt.alias, selected, opt.stdout)
}

func pickModel(stdin io.Reader, stdout io.Writer, entries []modelEntry) (string, error) {
	fmt.Fprintf(stdout, "\n%d model(s) available:\n", len(entries))
	for i, m := range entries {
		line := m.ID
		if m.Name != "" && m.Name != m.ID {
			line = fmt.Sprintf("%s (%s)", m.ID, m.Name)
		}
		fmt.Fprintf(stdout, "  %3d) %s\n", i+1, line)

View on GitHub (pinned to 49183d7e8d)

Solutions

  1. Skip the listing: picoclaw model add -b <base> -k <key> -m <model-id> -n <alias>
  2. Inspect the raw response with curl <api-base>/models to confirm the list is really empty
  3. On the provider side: add a payment method, fix key scopes, or load models on the self-hosted server
  4. Double-check --api-base points at the prefix that actually serves your models

Example fix

# before
$ picoclaw model add -b https://gateway.example.com/v1 -k sk-...
no models returned by https://gateway.example.com/v1

# after
$ picoclaw model add -b https://gateway.example.com/v1 -k sk-... -m deepseek-r1-250120 -n deepseek
Defensive patterns

Strategy: validation

Validate before calling

entries, err := fetchOpenAIModels(apiBase, apiKey)
if err != nil {
  return err
}
if len(entries) == 0 {
  return fmt.Errorf("no models returned by %s; pass -m <model-id> to add one anyway", apiBase)
}

Type guard

func isNoModelsError(err error) bool {
  return err != nil && strings.Contains(err.Error(), "no models returned by")
}

Try / catch

if err := runAdd(opt); err != nil {
  if isNoModelsError(err) {
    // re-run with -m <known-model-id> to bypass the empty listing
  }
  return err
}

Prevention

When it happens

Trigger: Provider returns an empty list — common before billing is set up, with keys scoped to no models, or on self-hosted servers (vLLM/ollama-compatible) started with no models loaded; a wrong --api-base pointing at a valid-but-empty endpoint version.

Common situations: Freshly created API accounts with no payment method; keys restricted to specific models with none allow-listed; gateways with no models routed; wrong base path hitting a stub endpoint.

Related errors


AI-assisted analysis of sipeed/picoclaw@49183d7e8d (2026-08-15). Data as JSON: /api/errors/ad2f5c08c565db27. Report an issue: GitHub.