Summary
rootly pulse create (v0.5.0) creates the pulse successfully, then exits non-zero because it can't parse the API's response:
Error: failed to create pulse: failed to parse response: json: cannot unmarshal array into Go struct field .data.attributes.services of type struct { Data []struct { Attributes struct { Name string "json:\"name\"" } "json:\"attributes\"" } "json:\"data\"" }
The pulse is recorded in Rootly (correct summary, source, services, environments, labels, refs). Only the CLI's post-create parsing fails, so the command reports failure for a request that succeeded.
Impact
rootlyhq/pulse-action (v2.0.0) builds its image from the latest rootly-cli release, so every GitHub Actions pulse now fails its step with the error above. Workflows that don't set continue-on-error go red on every deploy, even though the pulse arrived.
Reproduce
rootly pulse create \
--services=<a service slug> \
--environments=<an environment slug> \
--labels="service=email,ref=main" \
--source=github-actions \
"Deployed email to staging"
The API returns 201. The CLI prints the error above and exits 1.
Cause
CreatePulseCLI in internal/api/client.go expects services and environments in JSON:API relationship form:
Services *struct {
Data []struct {
Attributes struct {
Name string `json:"name"`
} `json:"attributes"`
} `json:"data"`
} `json:"services"`
But POST /v1/pulses (and GET /v1/pulses) returns them as flat arrays of objects inside data.attributes:
"services": [
{ "id": "…", "name": "Email", "slug": "email", … }
],
"environments": [
{ "id": "…", "name": "Staging", "slug": "staging", … }
]
json.Unmarshal of an array into that struct fails, which aborts the whole parse. The same mismatch applies to environments.
Suggested fix
Model both fields as flat arrays, matching the API:
Services []struct {
Name string `json:"name"`
} `json:"services"`
Environments []struct {
Name string `json:"name"`
} `json:"environments"`
Then map s.Name / e.Name into pulse.Services / pulse.Environments. Alternatively, treat a parse failure after a 2xx as a warning, since the pulse was created. A test in client_pulse_test.go with a real POST /v1/pulses response body that includes services and environments would catch this.
Environment
- rootly-cli v0.5.0 (latest, pulled by
rootlyhq/pulse-action@22355de7941ef67a661e0873006ec17b33224fb5, v2.0.0)
- GitHub Actions,
ubuntu-latest
- Observed 2026-09-24
Summary
rootly pulse create(v0.5.0) creates the pulse successfully, then exits non-zero because it can't parse the API's response:The pulse is recorded in Rootly (correct summary, source, services, environments, labels, refs). Only the CLI's post-create parsing fails, so the command reports failure for a request that succeeded.
Impact
rootlyhq/pulse-action(v2.0.0) builds its image from the latestrootly-clirelease, so every GitHub Actions pulse now fails its step with the error above. Workflows that don't setcontinue-on-errorgo red on every deploy, even though the pulse arrived.Reproduce
The API returns 201. The CLI prints the error above and exits 1.
Cause
CreatePulseCLIininternal/api/client.goexpectsservicesandenvironmentsin JSON:API relationship form:But
POST /v1/pulses(andGET /v1/pulses) returns them as flat arrays of objects insidedata.attributes:json.Unmarshalof an array into that struct fails, which aborts the whole parse. The same mismatch applies toenvironments.Suggested fix
Model both fields as flat arrays, matching the API:
Then map
s.Name/e.Nameintopulse.Services/pulse.Environments. Alternatively, treat a parse failure after a 2xx as a warning, since the pulse was created. A test inclient_pulse_test.gowith a realPOST /v1/pulsesresponse body that includes services and environments would catch this.Environment
rootlyhq/pulse-action@22355de7941ef67a661e0873006ec17b33224fb5, v2.0.0)ubuntu-latest