sipeed/picoclaw · error

get config %s: %w

Error message

get config %s: %w

What it means

getAccountConfigString wraps a failed get_config JSON-RPC call. The wrapped error is one of: *rpcError (code+message from the server, format 'deltachat rpc error %d: %s'), 'deltachat rpc: connection closed', 'rpc closed: <cause>' (failAll after stdout EOF), or a context error.

Source

Thrown at pkg/channels/deltachat/deltachat.go:1106

}

func (c *DeltaChatChannel) cleanupPendingAccount(ctx context.Context, accountID int64) {
	if accountID <= 0 || c.rpc == nil {
		return
	}
	stopCtx, cancel := context.WithTimeout(ctx, 10*time.Second)
	_, _ = c.rpc.call(stopCtx, "stop_ongoing_process", accountID)
	cancel()

	removeCtx, cancel := context.WithTimeout(ctx, 10*time.Second)
	_, _ = c.rpc.call(removeCtx, "remove_account", accountID)
	cancel()
}

func (c *DeltaChatChannel) getAccountConfigString(ctx context.Context, accountID int64, key string) (string, error) {
	raw, err := c.rpc.call(ctx, "get_config", accountID, key)
	if err != nil {
		return "", fmt.Errorf("get config %s: %w", key, err)
	}
	var value *string
	if err := json.Unmarshal(raw, &value); err != nil {
		return "", fmt.Errorf("decode config %s: %w", key, err)
	}
	if value == nil {
		return "", nil
	}
	return *value, nil
}

func (c *DeltaChatChannel) passwordRequiredError(reason string) error {
	return fmt.Errorf("deltachat: account %s is not configured in data_dir %s (%s)",
		c.config.Email, c.dataDir, reason)
}

func (c *DeltaChatChannel) applyProfileConfig(ctx context.Context, accountID int64) error {
	cfgMap := map[string]*string{}

View on GitHub (pinned to 49183d7e8d)

Solutions

  1. Probe server liveness with get_system_info (2s timeout, as the ready-loop does)
  2. Confirm the account still exists via get_all_accounts
  3. Restart PicoClaw so the RPC child is respawned and ensureAccount re-runs
Defensive patterns

Strategy: try-catch

Validate before calling

// Liveness probe before relying on get_config
func rpcAlive(c *rpcClient) bool {
    ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
    defer cancel()
    _, err := c.call(ctx, "get_system_info")
    return err == nil
}

Try / catch

addr, err := c.getAccountConfigString(ctx, id, key)
if err != nil {
    if strings.Contains(err.Error(), "rpc closed") || strings.Contains(err.Error(), "connection closed") {
        // transport gone: respawn server / restart channel instead of retrying the call
    }
    return "", err
}

Prevention

When it happens

Trigger: c.rpc.call(ctx, "get_config", accountID, key) fails: the RPC child process died, ctx was canceled, or the core rejected the account id / key.

Common situations: Stale accountID after an out-of-band remove_account; deltachat-rpc-server crash; shutdown race where the parent ctx is canceled first.

Related errors


AI-assisted analysis of sipeed/picoclaw@49183d7e8d (2026-08-15). Data as JSON: /api/errors/49e57f7f76c7b95a. Report an issue: GitHub.