Solana program return value missing from .rpc(), which gives only a signature — use set_return_data and meta.returnData
Symptom: a program handler declares -> Result<String> (or writes a value it wants to hand back), and the client does const v = await program.methods.newItem().rpc(). v is always a base58 transaction signature, never the value.
Cause: .rpc() returns the signature by design; a transaction has no return channel to the sender except the runtime's return data slot. On-chain, the mechanism is solana_program::program::set_return_data(&bytes) (Anchor sets this for you when an instruction has a declared return type), and a CPI caller reads it with get_return_data(). Off-chain, it surfaces as meta.returnData on a fetched or simulated transaction: { programId, data: [base64, "base64"] }.
Two concrete client paths:
// 1. simulate and read the value without landing a transaction
const out = await program.methods.newItem('id').view();
// 2. or land it, then read the return data off the confirmed transaction
const sig = await program.methods.newItem('id').rpc();
const tx = await connection.getTransaction(sig, { commitment: 'confirmed', maxSupportedTransactionVersion: 0 });
const raw = Buffer.from(tx.meta.returnData.data[0], 'base64');Constraints worth knowing before designing around this: return data is capped at 1024 bytes; only the most recent instruction's return data is visible, so in a multi-instruction transaction later instructions overwrite earlier ones; and .view() works by simulating, so it must not be used for instructions whose result depends on the state change they perform. The durable pattern for anything a client or another program needs later is to write it into an account, or emit an event/msg! line, rather than relying on return data.
Source: adapted from a Stack Exchange answer by Joe C (question by ZeroNine), https://solana.stackexchange.com/questions/9361/return-value-from-program-function — CC BY-SA 4.0