charmbracelet/crush · info

failed to marshal GraphQL request: %w

Error message

failed to marshal GraphQL request: %w

What it means

Wraps a json.Marshal error while serializing the GraphQL request payload in the sourcegraph tool (internal/agent/tools/sourcegraph.go:104-107). The payload is a statically typed struct with a string query and string variable, so marshalling can practically never fail; this is a defensive branch that only fires if encoding/json itself errors, which for plain strings requires invalid UTF-8 in the query or an unrecoverable encoder state.

Source

Thrown at internal/agent/tools/sourcegraph.go:106

				requestCtx, cancel = context.WithTimeout(ctx, time.Duration(params.Timeout)*time.Second)
				defer cancel()
			}

			type graphqlRequest struct {
				Query     string `json:"query"`
				Variables struct {
					Query string `json:"query"`
				} `json:"variables"`
			}

			request := graphqlRequest{
				Query: "query Search($query: String!) { search(query: $query, version: V2, patternType: keyword ) { results { matchCount, limitHit, resultCount, approximateResultCount, missing { name }, timedout { name }, indexUnavailable, results { __typename, ... on FileMatch { repository { name }, file { path, url, content }, lineMatches { preview, lineNumber, offsetAndLengths } } } } } }",
			}
			request.Variables.Query = params.Query

			graphqlQueryBytes, err := json.Marshal(request)
			if err != nil {
				return fantasy.ToolResponse{}, fmt.Errorf("failed to marshal GraphQL request: %w", err)
			}
			graphqlQuery := string(graphqlQueryBytes)

			req, err := http.NewRequestWithContext(
				requestCtx,
				"POST",
				"https://sourcegraph.com/.api/graphql",
				bytes.NewBuffer([]byte(graphqlQuery)),
			)
			if err != nil {
				return fantasy.ToolResponse{}, fmt.Errorf("failed to create request: %w", err)
			}

			req.Header.Set("Content-Type", "application/json")
			req.Header.Set("User-Agent", "crush/1.0")

			resp, err := client.Do(req)
			if err != nil {

View on GitHub (pinned to 7944b8e522)

Solutions

  1. Sanitize or validate params.Query as valid UTF-8 (utf8.ValidString) before building the request.
  2. Log the raw query parameter from the tool call to identify where the malformed input originated.
  3. Return a clear tool-level validation error for non-UTF-8 queries instead of a marshal failure.

Example fix

// before
githubQueryBytes, err := json.Marshal(request)

// after
if !utf8.ValidString(params.Query) {
    return fantasy.NewTextErrorResponse("query must be valid UTF-8"), nil
}
graphqlQueryBytes, err := json.Marshal(request)
Defensive patterns

Strategy: validation

Validate before calling

if !utf8.ValidString(params.Query) {
    return fantasy.NewTextErrorResponse("query must be valid UTF-8"), nil
}

Try / catch

if _, err := json.Marshal(request); err != nil {
    log.Printf("marshal failed for query %q", params.Query)
    return err
}

Prevention

When it happens

Trigger: json.Marshal(request) fails — in practice only if SourcegraphParams.Query contains invalid UTF-8 bytes (e.g. binary data passed by an LLM tool call into the query parameter), since all other fields are fixed strings.

Common situations: A model supplying a query with raw binary or invalid UTF-8 characters; almost never seen in normal operation because the struct contains no channels, funcs, cycles, or unsupported numeric types.

Related errors


AI-assisted analysis of charmbracelet/crush@7944b8e522 (2026-08-29). Data as JSON: /api/errors/165741b0b70b4797. Report an issue: GitHub.