gastownhall/beads · error
credential command returned unparseable JSON: %w
Error message
credential command returned unparseable JSON: %w
What it means
When the credential command's output starts with '{', parseCredential treats it as a JSON exec-credential envelope. If json.Unmarshal fails, the JSON is malformed and this error wraps the unmarshal failure. The command is supposed to emit either valid JSON or a bare token.
Source
Thrown at internal/creds/command.go:153
credCacheMu.Unlock()
return token, username, expiry, nil
}
// parseCredential extracts the token (and any username/expiry) from a helper's
// stdout. A JSON object is read as the ExecCredential/getToken envelope; otherwise
// the trimmed output is taken as a bare token. A bare value containing whitespace is
// rejected — it is almost always an error message, and using it as a credential
// would only fail confusingly downstream.
func parseCredential(raw []byte) (token, username string, expiry time.Time, err error) {
trimmed := bytes.TrimSpace(raw)
if len(trimmed) == 0 {
return "", "", time.Time{}, fmt.Errorf("credential command produced no output")
}
if trimmed[0] == '{' {
var c execCredential
if jerr := json.Unmarshal(trimmed, &c); jerr != nil {
return "", "", time.Time{}, fmt.Errorf("credential command returned unparseable JSON: %w", jerr)
}
token = c.Token
if token == "" {
token = c.AccessToken
}
if token == "" {
return "", "", time.Time{}, fmt.Errorf("credential command JSON has no token/access_token field")
}
switch {
case c.ExpirationTimestamp != "":
if t, perr := time.Parse(time.RFC3339, c.ExpirationTimestamp); perr == nil {
expiry = t
}
case c.ExpiresIn > 0:
expiry = time.Now().Add(time.Duration(c.ExpiresIn) * time.Second)
}
return token, c.Username, expiry, nil
}View on GitHub (pinned to 71377f2769)
Solutions
- Read the wrapped %w JSON syntax error to find the malformed offset.
- Run the credential command manually and inspect raw stdout for corruption or extra output.
- Fix the helper to emit valid JSON: {"token":"...","expirationTimestamp":"...RFC3339..."}.
- Alternatively make the helper print just a bare token (no braces) so the JSON path is skipped.
Example fix
// before
{"token: ghp_abc} // invalid JSON
// after
{"token":"ghp_abc","expirationTimestamp":"2026-01-01T00:00:00Z"} Defensive patterns
Strategy: validation
Validate before calling
var probe map[string]any
if err := json.Unmarshal(raw, &probe); err != nil {
// output is not valid JSON; fix helper output first
} Prevention
- Generate JSON with encoding/json in the helper instead of string concatenation.
- Ensure the helper writes nothing but the JSON envelope to stdout.
- Avoid proxies/log wrappers that inject text into stdout.
When it happens
Trigger: The helper prints a partial/truncated JSON document, pretty-printed output with a trailing error appended, or invalid JSON such as '{token: abc}' without quoting.
Common situations: A custom credential script emitting hand-built JSON with unquoted values; helper mixing JSON output with log lines; proxy/firewall injecting an error page before the JSON.
Related errors
- parsing JSON: %w
- failed to parse gh output: %w
- parse gh output: %w
- failed to parse JSONL line: %w
- failed to parse memory record: %w
AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30).
Data as JSON: /api/errors/69001dd96d22fe7d.
Report an issue: GitHub.