plandex-ai/plandex · error
error unmarshalling convo message: %v
Error message
error unmarshalling convo message: %v
What it means
GetConvoMessage read the message file but json.Unmarshal could not decode its bytes into a ConvoMessage. This is a data-integrity error indicating the stored JSON is invalid or its schema no longer matches the ConvoMessage struct expected by the running server version.
Source
Thrown at app/server/db/convo_helpers.go:96
})
return convo, nil
}
func GetConvoMessage(orgId, planId, messageId string) (*ConvoMessage, error) {
convoDir := getPlanConversationDir(orgId, planId)
filePath := filepath.Join(convoDir, messageId+".json")
bytes, err := os.ReadFile(filePath)
if err != nil {
return nil, fmt.Errorf("error reading convo message: %v", err)
}
var convoMessage ConvoMessage
err = json.Unmarshal(bytes, &convoMessage)
if err != nil {
return nil, fmt.Errorf("error unmarshalling convo message: %v", err)
}
return &convoMessage, nil
}
func StoreConvoMessage(repo *GitRepo, message *ConvoMessage, currentUserId, branch string, commit bool) (string, error) {
convoDir := getPlanConversationDir(message.OrgId, message.PlanId)
ts := time.Now().UTC()
if message.Id == "" {
message.Id = uuid.New().String()
}
message.CreatedAt = ts
bytes, err := json.Marshal(message)
View on GitHub (pinned to e2d772072e)
Solutions
- Validate the file with 'jq . <convoDir>/<messageId>.json' to pinpoint the JSON error and offset
- Repair or restore the message file from backup
- Delete the corrupt message file if it can be regenerated (partial replies are often re-storable via StorePartialReply)
- Run Plandex's data migration after version upgrades before serving plans
- Pin matching client/server versions so stored and expected schemas agree
Defensive patterns
Strategy: validation
Validate before calling
path := filepath.Join(getPlanConversationDir(orgId, planId), messageId+".json")
if data, err := os.ReadFile(path); err == nil {
var probe db.ConvoMessage
if err := json.Unmarshal(data, &probe); err != nil {
return fmt.Errorf("message %s is corrupt: %w", messageId, err)
}
if probe.Id == "" {
return fmt.Errorf("message %s missing required fields", messageId)
}
} Type guard
func isValidStoredConvoMessage(data []byte) bool {
var m db.ConvoMessage
return json.Unmarshal(data, &m) == nil && m.Id != "" && !m.CreatedAt.IsZero()
} Try / catch
msg, err := db.GetConvoMessage(orgId, planId, messageId)
if err != nil {
if strings.Contains(err.Error(), "unmarshalling convo message") {
backupAndQuarantine(path) // then surface as 422/500 data-corruption
}
return err
} Prevention
- Match server versions to stored data versions (run migrations)
- Never truncate writes: use temp-file + rename for storage writes
- Keep backups validated with jq before restore
- Avoid manual edits to stored message JSON
When it happens
Trigger: The message file is truncated/zero-length (interrupted write), manually edited and syntactically invalid, or was written by a different Plandex version whose field types changed (e.g. string vs number, changed object shape) so unmarshal fails on type mismatch.
Common situations: Server crash mid-write in StoreConvoMessage; Plandex upgrade/downgrade across a ConvoMessage schema change; operator hand-editing message JSON; corrupted backup restore.
Understand the failure class
Background: "failed to unmarshal" / json.Unmarshal errors: why parsing a response into a Go struct fails and how to fix it — this error's family across 23 libraries.
Related errors
- error unmarshalling convo file: %v
- error unmarshalling apply file: %v
- error unmarshalling accounts.json: %v
- refresh failed - marshal: %w
- error marshalling models: %v
AI-assisted analysis of plandex-ai/plandex@e2d772072e (2026-09-05).
Data as JSON: /api/errors/2d6e5304bca4d045.
Report an issue: GitHub.