Here's the formulation and Gurobi code:

**Decision Variables:**

* `s`: Number of student painters
* `f`: Number of full-time painters

**Objective Function:**

Minimize total wages: `200s + 500f`

**Constraints:**

* Total painters: `s + f >= 100`
* Minimum full-time painters: `f >= 30`
* Experience constraint: `f >= 0.5s`
* Non-negativity: `s >= 0`, `f >= 0`


```python
import gurobipy as gp
from gurobipy import GRB

try:
    # Create a new model
    model = gp.Model("Painter Optimization")

    # Create variables
    s = model.addVar(lb=0, vtype=GRB.CONTINUOUS, name="s") #students
    f = model.addVar(lb=0, vtype=GRB.CONTINUOUS, name="f") #full-time

    # Set objective
    model.setObjective(200*s + 500*f, GRB.MINIMIZE)

    # Add constraints
    model.addConstr(s + f >= 100, "Total painters")
    model.addConstr(f >= 30, "Min full-time")
    model.addConstr(f >= 0.5*s, "Experience")


    # Optimize model
    model.optimize()

    # Print solution
    if model.status == GRB.OPTIMAL:
        print(f"Optimal Solution Found:")
        print(f"Number of students: {s.x}")
        print(f"Number of full-time employees: {f.x}")
        print(f"Total wage bill: ${model.objVal}")
    elif model.status == GRB.INFEASIBLE:
        print("Model is infeasible.")
    else:
        print(f"Optimization ended with status: {model.status}")


except gp.GurobiError as e:
    print(f"Error code {e.errno}: {e}")

except AttributeError:
    print('Encountered an attribute error')
```
