vxcontrol/pentagi · error

resource %d not accessible

Error message

resource %d not accessible

What it means

The requested resource exists but belongs to a different user (r.UserID != uid), and the caller is not an admin. validateServiceResources scopes resources per-user: a non-admin may only reference their own resources, preventing horizontal privilege escalation through flow/assistant creation.

Source

Thrown at backend/pkg/server/services/assistants.go:677

	var recs []models.UserResource
	if err := db.Model(&models.UserResource{}).Where("id IN (?)", ids).Find(&recs).Error; err != nil {
		return nil, fmt.Errorf("failed to fetch resources: %w", err)
	}

	found := make(map[uint64]models.UserResource, len(recs))
	for _, r := range recs {
		found[r.ID] = r
	}

	result := make([]database.UserResource, 0, len(ids))
	for _, id := range ids {
		r, ok := found[id]
		if !ok {
			return nil, fmt.Errorf("resource %d not found", id)
		}
		if !isAdmin && r.UserID != uid {
			return nil, fmt.Errorf("resource %d not accessible", id)
		}
		result = append(result, database.UserResource{
			ID:        int64(r.ID),
			UserID:    int64(r.UserID),
			Hash:      r.Hash,
			Name:      r.Name,
			Path:      r.Path,
			Size:      r.Size,
			IsDir:     r.IsDir,
			CreatedAt: database.TimeToNullTime(r.CreatedAt),
			UpdatedAt: database.TimeToNullTime(r.UpdatedAt),
		})
	}

	return result, nil
}

View on GitHub (pinned to ea665308ba)

Solutions

  1. Use resource IDs owned by the authenticated user (list them via the resources endpoint as that user).
  2. Have an admin (privilege 'resources.admin') create the flow/assistant if cross-user resources are required.
  3. Re-create the resource under the calling user's account.
  4. If team sharing is the goal, extend the backend to support resource sharing groups rather than bypassing this check.
  5. Confirm the token used corresponds to the intended user (not another teammate's token).
Defensive patterns

Strategy: validation

Validate before calling

// verify ownership before attaching resources
var rec models.UserResource
if err := db.First(&rec, id).Error; err == nil {
    if rec.UserID != uid && !isAdmin {
        return fmt.Errorf("resource %d belongs to user %d, not caller %d", id, rec.UserID, uid)
    }
}

Type guard

func canAccessResource(r models.UserResource, uid uint64, privs []string) bool {
    return slices.Contains(privs, "resources.admin") || r.UserID == uid
}

Try / catch

_, err := validateServiceResources(ctx, uid, privs, ids)
if err != nil {
    if strings.Contains(err.Error(), "not accessible") {
        return nil, fmt.Errorf("one or more resources belong to another user; use your own resources or ask an admin")
    }
    return nil, err
}

Prevention

When it happens

Trigger: CreateFlowAssistant, PatchAssistant, CreateFlow, or PatchFlow where a non-admin user passes a valid resource ID owned by another user.

Common situations: Sharing resource IDs between teammates without knowing they are user-scoped; an automation service account trying to attach resources created by a human user; guessing/enumerating other users' resource IDs (correctly rejected).

Related errors


AI-assisted analysis of vxcontrol/pentagi@ea665308ba (2026-09-01). Data as JSON: /api/errors/8679601cf8ff9b3c. Report an issue: GitHub.