gastownhall/beads · warning

encoding string: %w

Error message

encoding string: %w

What it means

writeCanonicalMetadataString emits one JSON string (key or value) using the standard library's escaping via json.Marshal so both sides of a comparison escape identically. json.Marshal on a Go string cannot fail in current Go, so this error is defensive: it only fires if the standard library's marshaler returns an unexpected error, and it wraps it so the cause is preserved.

Source

Thrown at internal/storage/metadata_cas.go:221

			if err := writeCanonicalMetadataJSON(buf, typed[key]); err != nil {
				return err
			}
		}
		buf.WriteByte('}')
	default:
		// encoding/json produces only the cases above for an `any` target with
		// UseNumber set, so reaching this means the decoder changed under us.
		return fmt.Errorf("cannot canonicalize %T", value)
	}
	return nil
}

// writeCanonicalMetadataString emits a JSON string with the standard library's
// escaping, which both sides of a comparison go through identically.
func writeCanonicalMetadataString(buf *bytes.Buffer, s string) error {
	encoded, err := json.Marshal(s)
	if err != nil {
		return fmt.Errorf("encoding string: %w", err)
	}
	buf.Write(encoded)
	return nil
}

// truncateMetadataValue bounds a malformed value quoted back at a caller, so a
// megabyte of junk does not become a megabyte of error message.
func truncateMetadataValue(raw json.RawMessage) string {
	const limit = 64
	if len(raw) <= limit {
		return string(raw)
	}
	return string(raw[:limit]) + "…"
}

View on GitHub (pinned to 71377f2769)

Solutions

  1. Unwrap the error to read json.Marshal's underlying cause (check Go release notes for encoding/json behavior changes).
  2. Upgrade or pin the Go toolchain to a version where json.Marshal(string) is total.
  3. As a workaround, pre-encode the string yourself with json.Marshal and compare the encoded bytes.
  4. File an issue with the input string if a reproducible marshal failure exists.
Defensive patterns

Strategy: try-catch

Try / catch

if err := storage.CanonicalMetadataValue(raw); err != nil {
    if strings.Contains(err.Error(), "encoding string") {
        // standard-library marshal failure: report toolchain/runtime details
        return fmt.Errorf("canonicalizer string encode failed (go %s): %w", runtime.Version(), err)
    }
    return err
}

Prevention

When it happens

Trigger: Effectively unreachable for plain string inputs — reached only through writeCanonicalMetadataJSON during CanonicalMetadataValue if json.Marshal(string) ever returned an error (e.g. a future Go change or an unsupported rune scenario in the runtime).

Common situations: Developers effectively never hit this in production; if it appears, it signals a Go runtime/standard-library anomaly or code drift in the canonicalizer (the sibling 'cannot canonicalize %T' branch guards similar drift).

Related errors


AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30). Data as JSON: /api/errors/195ddbcf234500ca. Report an issue: GitHub.