googleapis/mcp-toolbox · error

error fetching LookML model %s: %w

Error message

error fetching LookML model %s: %w

What it means

getUnusedExplores fetches a single LookML model by name via the Looker SDK's LookmlModel(modelName, "", nil) to inspect its explores. When that per-model API call fails, the error is wrapped as "error fetching LookML model <name>: %w". Unlike the list-all failures, this one names the specific model, pointing to a model-level problem (deleted/renamed model, per-model permission, or transient API error).

Source

Thrown at internal/tools/looker/lookerhealthvacuum/lookerhealthvacuum.go:376

		return nil, err
	}

	var data []map[string]interface{}
	_ = json.Unmarshal([]byte(raw), &data)

	results := make(map[string]int)
	for _, row := range data {
		model, _ := row["query.model"].(string)
		count, _ := row["history.query_run_count"].(float64)
		results[model] = int(count)
	}
	return results, nil
}

func (t *vacuumTool) getUnusedExplores(ctx context.Context, modelName string) ([]string, error) {
	lookmlModel, err := t.SdkClient.LookmlModel(modelName, "", nil)
	if err != nil {
		return nil, fmt.Errorf("error fetching LookML model %s: %w", modelName, err)
	}

	var unusedExplores []string
	if lookmlModel.Explores != nil {
		for _, e := range *lookmlModel.Explores {
			limit := "1"
			queryCountQueryBody := &v4.WriteQuery{
				Model:  "system__activity",
				View:   "history",
				Fields: &[]string{"history.query_run_count"},
				Filters: &map[string]any{
					"query.model":             modelName,
					"query.view":              *e.Name,
					"history.created_date":    fmt.Sprintf("%d days", t.timeframe),
					"history.query_run_count": fmt.Sprintf(">%d", t.minQueries-1),
					"user.dev_branch_name":    "NULL",
				},
				Limit: &limit,

View on GitHub (pinned to 8cc6e09de2)

Solutions

  1. Confirm the model named in the error still exists and check its exact name casing in Looker.
  2. Verify the API user has permission to read that specific model/workspace.
  3. Add retry/backoff around per-model calls to survive 429s and transient failures.
  4. Re-run the vacuum to pick up models changed by a concurrent LookML deploy.

Example fix

// before
lookmlModel, err := t.SdkClient.LookmlModel(modelName, "", nil)
if err != nil {
    return nil, fmt.Errorf("error fetching LookML model %s: %w", modelName, err)
}

// after — tolerate a model vanishing mid-run
lookmlModel, err := t.SdkClient.LookmlModel(modelName, "", nil)
if err != nil {
    logger.WarnContext(ctx, "skipping model", "model", modelName, "err", err)
    return nil, nil
}
Defensive patterns

Strategy: try-catch

Validate before calling

// confirm the model exists before deep-fetching
models, err := sdk.AllLookmlModels(v4.RequestAllLookmlModels{}, nil)
if err != nil { return err }
found := false
for _, m := range models {
    if m.Name != nil && *m.Name == modelName { found = true }
}
if !found { return fmt.Errorf("model %q not found", modelName) }

Try / catch

lookmlModel, err := sdk.LookmlModel(modelName, "", nil)
if err != nil {
    logger.WarnContext(ctx, "skipping model", "model", modelName, "err", err)
    return nil, nil // tolerate per-model failures during bulk vacuum
}

Prevention

When it happens

Trigger: t.SdkClient.LookmlModel(modelName, "", nil) returns an error while iterating models discovered earlier: the model was deleted or renamed between calls, the API user cannot read that model, a 404 from Looker, rate limiting, or network interruption mid-run.

Common situations: Concurrent LookML deploys removing models during a long vacuum run; dev-mode model not visible to the API user's workspace; permission-scoped roles; 429 rate limit triggered by iterating many models rapidly.

Related errors


AI-assisted analysis of googleapis/mcp-toolbox@8cc6e09de2 (2026-09-05). Data as JSON: /api/errors/695fc88a1c46133a. Report an issue: GitHub.